| @@ -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 <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, | |||
| JucerDocument& document, | |||
| @@ -386,6 +439,8 @@ void ComponentTypeHandler::getEditableProperties (Component* component, | |||
| if (dynamic_cast <SettableTooltipClient*> (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; | |||
| } | |||
| @@ -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<int>& setOfRowsToBeSelected) | |||
| { | |||
| selected = setOfRowsToBeSelected; | |||
| selected.removeRange (totalItems, 0x7fffffff - totalItems); | |||
| selected.removeRange (totalItems, INT_MAX - totalItems); | |||
| if (! isRowSelected (lastRowSelected)) | |||
| lastRowSelected = -1; | |||
| @@ -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; | |||
| @@ -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) | |||
| @@ -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. | |||
| @@ -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 <Componen | |||
| } | |||
| } | |||
| static Component* getIncrementedComponent (Component* const current, const int delta) | |||
| static Component* getIncrementedComponent (Component* const current, const int delta) throw() | |||
| { | |||
| Component* focusContainer = current->getParentComponent(); | |||
| @@ -108,9 +117,11 @@ static Component* getIncrementedComponent (Component* const current, const int d | |||
| Array <Component*> 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. | |||
| 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 | |||
| { | |||
| @@ -218,7 +218,7 @@ public: | |||
| { | |||
| ++accessCounter; | |||
| int oldestCounter = 0x7fffffff; | |||
| int oldestCounter = INT_MAX; | |||
| int oldestIndex = 0; | |||
| for (int i = numGlyphs; --i >= 0;) | |||
| @@ -476,7 +476,7 @@ public: | |||
| } | |||
| int replaceIndex = 0; | |||
| int bestLastUsageCount = 0x7fffffff; | |||
| int bestLastUsageCount = INT_MAX; | |||
| for (i = faces.size(); --i >= 0;) | |||
| { | |||
| @@ -826,7 +826,7 @@ void XmlElement::insertChildElement (XmlElement* const newNode, | |||
| else | |||
| { | |||
| if (indexToInsertAt < 0) | |||
| indexToInsertAt = 0x7fffffff; | |||
| indexToInsertAt = INT_MAX; | |||
| XmlElement* child = firstChildElement; | |||