| @@ -42,30 +42,31 @@ public: | |||||
| loadData(); | loadData(); | ||||
| // Create our table component and add it to this component.. | // Create our table component and add it to this component.. | ||||
| addAndMakeVisible (table = new TableListBox ("demo table", this)); | |||||
| addAndMakeVisible (&table); | |||||
| table.setModel (this); | |||||
| // give it a border | // give it a border | ||||
| table->setColour (ListBox::outlineColourId, Colours::grey); | |||||
| table->setOutlineThickness (1); | |||||
| table.setColour (ListBox::outlineColourId, Colours::grey); | |||||
| table.setOutlineThickness (1); | |||||
| // Add some columns to the table header, based on the column list in our database.. | // Add some columns to the table header, based on the column list in our database.. | ||||
| forEachXmlChildElement (*columnList, columnXml) | forEachXmlChildElement (*columnList, columnXml) | ||||
| { | { | ||||
| table->getHeader()->addColumn (columnXml->getStringAttribute ("name"), | |||||
| columnXml->getIntAttribute ("columnId"), | |||||
| columnXml->getIntAttribute ("width"), | |||||
| 50, 400, | |||||
| TableHeaderComponent::defaultFlags); | |||||
| table.getHeader().addColumn (columnXml->getStringAttribute ("name"), | |||||
| columnXml->getIntAttribute ("columnId"), | |||||
| columnXml->getIntAttribute ("width"), | |||||
| 50, 400, | |||||
| TableHeaderComponent::defaultFlags); | |||||
| } | } | ||||
| // we could now change some initial settings.. | // we could now change some initial settings.. | ||||
| table->getHeader()->setSortColumnId (1, true); // sort forwards by the ID column | |||||
| table->getHeader()->setColumnVisible (7, false); // hide the "length" column until the user shows it | |||||
| table.getHeader().setSortColumnId (1, true); // sort forwards by the ID column | |||||
| table.getHeader().setColumnVisible (7, false); // hide the "length" column until the user shows it | |||||
| // un-comment this line to have a go of stretch-to-fit mode | // un-comment this line to have a go of stretch-to-fit mode | ||||
| // table->getHeader()->setStretchToFitActive (true); | |||||
| // table.getHeader().setStretchToFitActive (true); | |||||
| table->setMultipleSelectionEnabled (true); | |||||
| table.setMultipleSelectionEnabled (true); | |||||
| } | } | ||||
| ~TableDemoComponent() | ~TableDemoComponent() | ||||
| @@ -119,7 +120,7 @@ public: | |||||
| DemoDataSorter sorter (getAttributeNameForColumnId (newSortColumnId), isForwards); | DemoDataSorter sorter (getAttributeNameForColumnId (newSortColumnId), isForwards); | ||||
| dataList->sortChildElements (sorter); | dataList->sortChildElements (sorter); | ||||
| table->updateContent(); | |||||
| table.updateContent(); | |||||
| } | } | ||||
| } | } | ||||
| @@ -190,14 +191,14 @@ public: | |||||
| void resized() | void resized() | ||||
| { | { | ||||
| // position our table with a gap around its edge | // position our table with a gap around its edge | ||||
| table->setBoundsInset (BorderSize (8)); | |||||
| table.setBoundsInset (BorderSize (8)); | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| juce_UseDebuggingNewOperator | juce_UseDebuggingNewOperator | ||||
| private: | private: | ||||
| ScopedPointer<TableListBox> table; // the table component itself | |||||
| TableListBox table; // the table component itself | |||||
| Font font; | Font font; | ||||
| ScopedPointer<XmlElement> demoData; // This is the XML document loaded from the embedded file "demo table data.xml" | ScopedPointer<XmlElement> demoData; // This is the XML document loaded from the embedded file "demo table data.xml" | ||||
| @@ -142,7 +142,7 @@ public: | |||||
| } | } | ||||
| else if (pageName == keysPage) | else if (pageName == keysPage) | ||||
| { | { | ||||
| return new KeyMappingEditorComponent (commandManager->getKeyMappings(), true); | |||||
| return new KeyMappingEditorComponent (*commandManager->getKeyMappings(), true); | |||||
| } | } | ||||
| else if (pageName == aboutPage) | else if (pageName == aboutPage) | ||||
| { | { | ||||
| @@ -95,11 +95,11 @@ ResourceEditorPanel::ResourceEditorPanel (JucerDocument& document_) | |||||
| delButton->setEnabled (false); | delButton->setEnabled (false); | ||||
| addAndMakeVisible (listBox = new TableListBox (String::empty, this)); | addAndMakeVisible (listBox = new TableListBox (String::empty, this)); | ||||
| listBox->getHeader()->addColumn (T("name"), 1, 150, 80, 400); | |||||
| listBox->getHeader()->addColumn (T("original file"), 2, 350, 80, 800); | |||||
| listBox->getHeader()->addColumn (T("size"), 3, 100, 40, 150); | |||||
| listBox->getHeader()->addColumn (T("reload"), 4, 100, 100, 100, TableHeaderComponent::notResizableOrSortable); | |||||
| listBox->getHeader()->setStretchToFitActive (true); | |||||
| listBox->getHeader().addColumn (T("name"), 1, 150, 80, 400); | |||||
| listBox->getHeader().addColumn (T("original file"), 2, 350, 80, 800); | |||||
| listBox->getHeader().addColumn (T("size"), 3, 100, 40, 150); | |||||
| listBox->getHeader().addColumn (T("reload"), 4, 100, 100, 100, TableHeaderComponent::notResizableOrSortable); | |||||
| listBox->getHeader().setStretchToFitActive (true); | |||||
| listBox->setColour (ListBox::outlineColourId, Colours::darkgrey); | listBox->setColour (ListBox::outlineColourId, Colours::darkgrey); | ||||
| listBox->setOutlineThickness (1); | listBox->setOutlineThickness (1); | ||||
| @@ -64,7 +64,7 @@ | |||||
| */ | */ | ||||
| #define JUCE_MAJOR_VERSION 1 | #define JUCE_MAJOR_VERSION 1 | ||||
| #define JUCE_MINOR_VERSION 52 | #define JUCE_MINOR_VERSION 52 | ||||
| #define JUCE_BUILDNUMBER 89 | |||||
| #define JUCE_BUILDNUMBER 90 | |||||
| /** Current Juce version number. | /** Current Juce version number. | ||||
| @@ -26721,15 +26721,14 @@ public: | |||||
| Never override this method! Use hitTest to create custom hit regions. | Never override this method! Use hitTest to create custom hit regions. | ||||
| @param x the x co-ordinate to test, relative to this component's left hand edge. | |||||
| @param y the y co-ordinate to test, relative to this component's top edge. | |||||
| @param point the x co-ordinate to test, relative to this component's top-left. | |||||
| @returns true if the point is within the component's hit-test area, but only if | @returns true if the point is within the component's hit-test area, but only if | ||||
| that part of the component isn't clipped by its parent component. Note | that part of the component isn't clipped by its parent component. Note | ||||
| that this won't take into account any overlapping sibling components | that this won't take into account any overlapping sibling components | ||||
| which might be in the way - for that, see reallyContains() | which might be in the way - for that, see reallyContains() | ||||
| @see hitTest, reallyContains, getComponentAt | @see hitTest, reallyContains, getComponentAt | ||||
| */ | */ | ||||
| virtual bool contains (int x, int y); | |||||
| bool contains (const Point<int>& point); | |||||
| /** Returns true if a given point lies in this component, taking any overlapping | /** Returns true if a given point lies in this component, taking any overlapping | ||||
| siblings into account. | siblings into account. | ||||
| @@ -27914,6 +27913,9 @@ public: | |||||
| /** If the component is valid, this deletes it and sets this pointer to null. */ | /** If the component is valid, this deletes it and sets this pointer to null. */ | ||||
| void deleteAndZero() { delete comp; jassert (comp == 0); } | void deleteAndZero() { delete comp; jassert (comp == 0); } | ||||
| bool operator== (ComponentType* component) const throw() { return comp == component; } | |||||
| bool operator!= (ComponentType* component) const throw() { return comp != component; } | |||||
| juce_UseDebuggingNewOperator | juce_UseDebuggingNewOperator | ||||
| private: | private: | ||||
| @@ -28056,8 +28058,6 @@ private: | |||||
| const Rectangle<int>& clipRect, const Component* const compToAvoid) const; | const Rectangle<int>& clipRect, const Component* const compToAvoid) const; | ||||
| void clipObscuredRegions (Graphics& g, const Rectangle<int>& clipRect, int deltaX, int deltaY) const; | void clipObscuredRegions (Graphics& g, const Rectangle<int>& clipRect, int deltaX, int deltaY) const; | ||||
| // how much of the component is not off the edges of its parents | |||||
| const Rectangle<int> getUnclippedArea() const; | |||||
| void sendVisibilityChangeMessage(); | void sendVisibilityChangeMessage(); | ||||
| const Rectangle<int> getParentOrMainMonitorBounds() const; | const Rectangle<int> getParentOrMainMonitorBounds() const; | ||||
| @@ -28067,9 +28067,14 @@ private: | |||||
| // implement its methods instead of this Component method). | // implement its methods instead of this Component method). | ||||
| virtual void filesDropped (const StringArray&, int, int) {} | virtual void filesDropped (const StringArray&, int, int) {} | ||||
| // components aren't allowed to have copy constructors, as this would mess up parent | |||||
| // hierarchies. You might need to give your subclasses a private dummy constructor like | |||||
| // this one to avoid compiler warnings. | |||||
| // This is included here to cause an error if you use or overload it - it has been deprecated in | |||||
| // favour of contains (const Point<int>&) | |||||
| void contains (int, int); | |||||
| /* Components aren't allowed to have copy constructors, as this would mess up parent hierarchies. | |||||
| You might need to give your subclasses a private dummy constructor like this one to avoid | |||||
| compiler warnings. | |||||
| */ | |||||
| Component (const Component&); | Component (const Component&); | ||||
| Component& operator= (const Component&); | Component& operator= (const Component&); | ||||
| @@ -36739,6 +36744,7 @@ private: | |||||
| ScrollBar horizontalScrollBar; | ScrollBar horizontalScrollBar; | ||||
| void updateVisibleArea(); | void updateVisibleArea(); | ||||
| void deleteContentComp(); | |||||
| Viewport (const Viewport&); | Viewport (const Viewport&); | ||||
| Viewport& operator= (const Viewport&); | Viewport& operator= (const Viewport&); | ||||
| @@ -37105,6 +37111,7 @@ private: | |||||
| friend class PopupMenuCustomComponent; | friend class PopupMenuCustomComponent; | ||||
| friend class MenuBarComponent; | friend class MenuBarComponent; | ||||
| friend class OwnedArray <Item>; | friend class OwnedArray <Item>; | ||||
| friend class OwnedArray <ItemComponent>; | |||||
| friend class ScopedPointer <Window>; | friend class ScopedPointer <Window>; | ||||
| OwnedArray <Item> items; | OwnedArray <Item> items; | ||||
| @@ -46035,12 +46042,12 @@ public: | |||||
| juce_UseDebuggingNewOperator | juce_UseDebuggingNewOperator | ||||
| private: | private: | ||||
| Button* missingItemsButton; | |||||
| ScopedPointer<Button> missingItemsButton; | |||||
| bool vertical, isEditingActive; | bool vertical, isEditingActive; | ||||
| ToolbarItemStyle toolbarStyle; | ToolbarItemStyle toolbarStyle; | ||||
| class MissingItemsComponent; | class MissingItemsComponent; | ||||
| friend class MissingItemsComponent; | friend class MissingItemsComponent; | ||||
| Array <ToolbarItemComponent*> items; | |||||
| OwnedArray <ToolbarItemComponent> items; | |||||
| friend class ItemDragAndDropOverlayComponent; | friend class ItemDragAndDropOverlayComponent; | ||||
| static const char* const toolbarDragDescriptor; | static const char* const toolbarDragDescriptor; | ||||
| @@ -48514,8 +48521,8 @@ public: | |||||
| The model pointer passed-in can be null, in which case you can set it later | The model pointer passed-in can be null, in which case you can set it later | ||||
| with setModel(). | with setModel(). | ||||
| */ | */ | ||||
| TableListBox (const String& componentName, | |||||
| TableListBoxModel* model); | |||||
| TableListBox (const String& componentName = String::empty, | |||||
| TableListBoxModel* model = 0); | |||||
| /** Destructor. */ | /** Destructor. */ | ||||
| ~TableListBox(); | ~TableListBox(); | ||||
| @@ -48528,7 +48535,7 @@ public: | |||||
| TableListBoxModel* getModel() const { return model; } | TableListBoxModel* getModel() const { return model; } | ||||
| /** Returns the header component being used in this table. */ | /** Returns the header component being used in this table. */ | ||||
| TableHeaderComponent* getHeader() const { return header; } | |||||
| TableHeaderComponent& getHeader() const { return *header; } | |||||
| /** Changes the height of the table header component. | /** Changes the height of the table header component. | ||||
| @see getHeaderHeight | @see getHeaderHeight | ||||
| @@ -52609,23 +52616,18 @@ private: | |||||
| @see KeyPressMappingSet | @see KeyPressMappingSet | ||||
| */ | */ | ||||
| class JUCE_API KeyMappingEditorComponent : public Component, | |||||
| public TreeViewItem, | |||||
| public ChangeListener, | |||||
| private ButtonListener // (can't use Button::Listener due to idiotic VC2005 bug) | |||||
| class JUCE_API KeyMappingEditorComponent : public Component | |||||
| { | { | ||||
| public: | public: | ||||
| /** Creates a KeyMappingEditorComponent. | /** Creates a KeyMappingEditorComponent. | ||||
| @param mappingSet this is the set of mappings to display and | |||||
| edit. Make sure the mappings object is not | |||||
| deleted before this component! | |||||
| @param showResetToDefaultButton if true, then at the bottom of the | |||||
| list, the component will include a 'reset to | |||||
| defaults' button. | |||||
| @param mappingSet this is the set of mappings to display and edit. Make sure the | |||||
| mappings object is not deleted before this component! | |||||
| @param showResetToDefaultButton if true, then at the bottom of the list, the | |||||
| component will include a 'reset to defaults' button. | |||||
| */ | */ | ||||
| KeyMappingEditorComponent (KeyPressMappingSet* mappingSet, | |||||
| KeyMappingEditorComponent (KeyPressMappingSet& mappingSet, | |||||
| bool showResetToDefaultButton); | bool showResetToDefaultButton); | ||||
| /** Destructor. */ | /** Destructor. */ | ||||
| @@ -52639,9 +52641,8 @@ public: | |||||
| void setColours (const Colour& mainBackground, | void setColours (const Colour& mainBackground, | ||||
| const Colour& textColour); | const Colour& textColour); | ||||
| /** Returns the KeyPressMappingSet that this component is acting upon. | |||||
| */ | |||||
| KeyPressMappingSet* getMappings() const throw() { return mappings; } | |||||
| /** Returns the KeyPressMappingSet that this component is acting upon. */ | |||||
| KeyPressMappingSet& getMappings() const throw() { return mappings; } | |||||
| /** Can be overridden if some commands need to be excluded from the list. | /** Can be overridden if some commands need to be excluded from the list. | ||||
| @@ -52686,29 +52687,24 @@ public: | |||||
| void parentHierarchyChanged(); | void parentHierarchyChanged(); | ||||
| /** @internal */ | /** @internal */ | ||||
| void resized(); | void resized(); | ||||
| /** @internal */ | |||||
| void changeListenerCallback (void*); | |||||
| /** @internal */ | |||||
| bool mightContainSubItems(); | |||||
| /** @internal */ | |||||
| const String getUniqueName() const; | |||||
| /** @internal */ | |||||
| void buttonClicked (Button* button); | |||||
| juce_UseDebuggingNewOperator | juce_UseDebuggingNewOperator | ||||
| private: | private: | ||||
| friend class KeyMappingTreeViewItem; | |||||
| friend class KeyCategoryTreeViewItem; | |||||
| friend class KeyMappingItemComponent; | |||||
| friend class KeyMappingChangeButton; | |||||
| KeyPressMappingSet* mappings; | |||||
| KeyPressMappingSet& mappings; | |||||
| TreeView tree; | TreeView tree; | ||||
| TextButton resetButton; | TextButton resetButton; | ||||
| void assignNewKey (CommandID commandID, int index); | |||||
| class TopLevelItem; | |||||
| class ChangeKeyButton; | |||||
| class MappingItem; | |||||
| class CategoryItem; | |||||
| class ItemComponent; | |||||
| friend class TopLevelItem; | |||||
| friend class OwnedArray <ChangeKeyButton>; | |||||
| friend class ScopedPointer<TopLevelItem>; | |||||
| ScopedPointer<TopLevelItem> treeItem; | |||||
| KeyMappingEditorComponent (const KeyMappingEditorComponent&); | KeyMappingEditorComponent (const KeyMappingEditorComponent&); | ||||
| KeyMappingEditorComponent& operator= (const KeyMappingEditorComponent&); | KeyMappingEditorComponent& operator= (const KeyMappingEditorComponent&); | ||||
| @@ -60143,6 +60139,7 @@ public: | |||||
| of (0, 0). | of (0, 0). | ||||
| */ | */ | ||||
| virtual void setOrigin (int x, int y) = 0; | virtual void setOrigin (int x, int y) = 0; | ||||
| virtual void addTransform (const AffineTransform& transform) = 0; | |||||
| virtual bool clipToRectangle (const Rectangle<int>& r) = 0; | virtual bool clipToRectangle (const Rectangle<int>& r) = 0; | ||||
| virtual bool clipToRectangleList (const RectangleList& clipRegion) = 0; | virtual bool clipToRectangleList (const RectangleList& clipRegion) = 0; | ||||
| @@ -60204,6 +60201,7 @@ public: | |||||
| bool isVectorDevice() const; | bool isVectorDevice() const; | ||||
| void setOrigin (int x, int y); | void setOrigin (int x, int y); | ||||
| void addTransform (const AffineTransform& transform); | |||||
| bool clipToRectangle (const Rectangle<int>& r); | bool clipToRectangle (const Rectangle<int>& r); | ||||
| bool clipToRectangleList (const RectangleList& clipRegion); | bool clipToRectangleList (const RectangleList& clipRegion); | ||||
| @@ -60301,6 +60299,7 @@ public: | |||||
| bool isVectorDevice() const; | bool isVectorDevice() const; | ||||
| void setOrigin (int x, int y); | void setOrigin (int x, int y); | ||||
| void addTransform (const AffineTransform& transform); | |||||
| bool clipToRectangle (const Rectangle<int>& r); | bool clipToRectangle (const Rectangle<int>& r); | ||||
| bool clipToRectangleList (const RectangleList& clipRegion); | bool clipToRectangleList (const RectangleList& clipRegion); | ||||
| @@ -33,7 +33,7 @@ | |||||
| */ | */ | ||||
| #define JUCE_MAJOR_VERSION 1 | #define JUCE_MAJOR_VERSION 1 | ||||
| #define JUCE_MINOR_VERSION 52 | #define JUCE_MINOR_VERSION 52 | ||||
| #define JUCE_BUILDNUMBER 89 | |||||
| #define JUCE_BUILDNUMBER 90 | |||||
| /** Current Juce version number. | /** Current Juce version number. | ||||
| @@ -40,13 +40,10 @@ ComboBox::ComboBox (const String& name) | |||||
| isButtonDown (false), | isButtonDown (false), | ||||
| separatorPending (false), | separatorPending (false), | ||||
| menuActive (false), | menuActive (false), | ||||
| label (0) | |||||
| noChoicesMessage (TRANS("(no choices)")) | |||||
| { | { | ||||
| noChoicesMessage = TRANS("(no choices)"); | |||||
| setRepaintsOnMouseActivity (true); | setRepaintsOnMouseActivity (true); | ||||
| lookAndFeelChanged(); | lookAndFeelChanged(); | ||||
| currentId.addListener (this); | currentId.addListener (this); | ||||
| } | } | ||||
| @@ -58,7 +55,6 @@ ComboBox::~ComboBox() | |||||
| PopupMenu::dismissAllActiveMenus(); | PopupMenu::dismissAllActiveMenus(); | ||||
| label = 0; | label = 0; | ||||
| deleteAllChildren(); | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -429,30 +425,33 @@ void ComboBox::lookAndFeelChanged() | |||||
| { | { | ||||
| repaint(); | repaint(); | ||||
| Label* const newLabel = getLookAndFeel().createComboBoxTextBox (*this); | |||||
| if (label != 0) | |||||
| { | { | ||||
| newLabel->setEditable (label->isEditable()); | |||||
| newLabel->setJustificationType (label->getJustificationType()); | |||||
| newLabel->setTooltip (label->getTooltip()); | |||||
| newLabel->setText (label->getText(), false); | |||||
| } | |||||
| ScopedPointer <Label> newLabel (getLookAndFeel().createComboBoxTextBox (*this)); | |||||
| jassert (newLabel != 0); | |||||
| if (label != 0) | |||||
| { | |||||
| newLabel->setEditable (label->isEditable()); | |||||
| newLabel->setJustificationType (label->getJustificationType()); | |||||
| newLabel->setTooltip (label->getTooltip()); | |||||
| newLabel->setText (label->getText(), false); | |||||
| } | |||||
| label = newLabel; | |||||
| label = newLabel; | |||||
| } | |||||
| addAndMakeVisible (newLabel); | |||||
| addAndMakeVisible (label); | |||||
| newLabel->addListener (this); | |||||
| newLabel->addMouseListener (this, false); | |||||
| label->addListener (this); | |||||
| label->addMouseListener (this, false); | |||||
| newLabel->setColour (Label::backgroundColourId, Colours::transparentBlack); | |||||
| newLabel->setColour (Label::textColourId, findColour (ComboBox::textColourId)); | |||||
| label->setColour (Label::backgroundColourId, Colours::transparentBlack); | |||||
| label->setColour (Label::textColourId, findColour (ComboBox::textColourId)); | |||||
| newLabel->setColour (TextEditor::textColourId, findColour (ComboBox::textColourId)); | |||||
| newLabel->setColour (TextEditor::backgroundColourId, Colours::transparentBlack); | |||||
| newLabel->setColour (TextEditor::highlightColourId, findColour (TextEditor::highlightColourId)); | |||||
| newLabel->setColour (TextEditor::outlineColourId, Colours::transparentBlack); | |||||
| label->setColour (TextEditor::textColourId, findColour (ComboBox::textColourId)); | |||||
| label->setColour (TextEditor::backgroundColourId, Colours::transparentBlack); | |||||
| label->setColour (TextEditor::highlightColourId, findColour (TextEditor::highlightColourId)); | |||||
| label->setColour (TextEditor::outlineColourId, Colours::transparentBlack); | |||||
| resized(); | resized(); | ||||
| } | } | ||||
| @@ -465,27 +464,23 @@ void ComboBox::colourChanged() | |||||
| //============================================================================== | //============================================================================== | ||||
| bool ComboBox::keyPressed (const KeyPress& key) | bool ComboBox::keyPressed (const KeyPress& key) | ||||
| { | { | ||||
| bool used = false; | |||||
| if (key.isKeyCode (KeyPress::upKey) | |||||
| || key.isKeyCode (KeyPress::leftKey)) | |||||
| if (key.isKeyCode (KeyPress::upKey) || key.isKeyCode (KeyPress::leftKey)) | |||||
| { | { | ||||
| setSelectedItemIndex (jmax (0, getSelectedItemIndex() - 1)); | setSelectedItemIndex (jmax (0, getSelectedItemIndex() - 1)); | ||||
| used = true; | |||||
| return true; | |||||
| } | } | ||||
| else if (key.isKeyCode (KeyPress::downKey) | |||||
| || key.isKeyCode (KeyPress::rightKey)) | |||||
| else if (key.isKeyCode (KeyPress::downKey) || key.isKeyCode (KeyPress::rightKey)) | |||||
| { | { | ||||
| setSelectedItemIndex (jmin (getSelectedItemIndex() + 1, getNumItems() - 1)); | setSelectedItemIndex (jmin (getSelectedItemIndex() + 1, getNumItems() - 1)); | ||||
| used = true; | |||||
| return true; | |||||
| } | } | ||||
| else if (key.isKeyCode (KeyPress::returnKey)) | else if (key.isKeyCode (KeyPress::returnKey)) | ||||
| { | { | ||||
| showPopup(); | showPopup(); | ||||
| used = true; | |||||
| return true; | |||||
| } | } | ||||
| return used; | |||||
| return false; | |||||
| } | } | ||||
| bool ComboBox::keyStateChanged (const bool isKeyDown) | bool ComboBox::keyStateChanged (const bool isKeyDown) | ||||
| @@ -499,17 +494,9 @@ bool ComboBox::keyStateChanged (const bool isKeyDown) | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| void ComboBox::focusGained (FocusChangeType) | |||||
| { | |||||
| repaint(); | |||||
| } | |||||
| void ComboBox::focusGained (FocusChangeType) { repaint(); } | |||||
| void ComboBox::focusLost (FocusChangeType) { repaint(); } | |||||
| void ComboBox::focusLost (FocusChangeType) | |||||
| { | |||||
| repaint(); | |||||
| } | |||||
| //============================================================================== | |||||
| void ComboBox::labelTextChanged (Label*) | void ComboBox::labelTextChanged (Label*) | ||||
| { | { | ||||
| triggerAsyncUpdate(); | triggerAsyncUpdate(); | ||||
| @@ -582,11 +569,8 @@ void ComboBox::mouseDown (const MouseEvent& e) | |||||
| isButtonDown = isEnabled(); | isButtonDown = isEnabled(); | ||||
| if (isButtonDown | |||||
| && (e.eventComponent == this || ! label->isEditable())) | |||||
| { | |||||
| if (isButtonDown && (e.eventComponent == this || ! label->isEditable())) | |||||
| showPopup(); | showPopup(); | ||||
| } | |||||
| } | } | ||||
| void ComboBox::mouseDrag (const MouseEvent& e) | void ComboBox::mouseDrag (const MouseEvent& e) | ||||
| @@ -332,7 +332,7 @@ void Label::mouseUp (const MouseEvent& e) | |||||
| { | { | ||||
| if (editSingleClick | if (editSingleClick | ||||
| && e.mouseWasClicked() | && e.mouseWasClicked() | ||||
| && contains (e.x, e.y) | |||||
| && contains (e.getPosition()) | |||||
| && ! e.mods.isPopupMenu()) | && ! e.mods.isPopupMenu()) | ||||
| { | { | ||||
| showEditor(); | showEditor(); | ||||
| @@ -36,51 +36,37 @@ BEGIN_JUCE_NAMESPACE | |||||
| //============================================================================== | //============================================================================== | ||||
| static const char* const tableColumnPropertyTag = "_tableColumnID"; | |||||
| class TableListRowComp : public Component, | class TableListRowComp : public Component, | ||||
| public TooltipClient | public TooltipClient | ||||
| { | { | ||||
| public: | public: | ||||
| TableListRowComp (TableListBox& owner_) | TableListRowComp (TableListBox& owner_) | ||||
| : owner (owner_), | |||||
| row (-1), | |||||
| isSelected (false) | |||||
| : owner (owner_), row (-1), isSelected (false) | |||||
| { | { | ||||
| } | } | ||||
| ~TableListRowComp() | |||||
| { | |||||
| deleteAllChildren(); | |||||
| } | |||||
| void paint (Graphics& g) | void paint (Graphics& g) | ||||
| { | { | ||||
| TableListBoxModel* const model = owner.getModel(); | TableListBoxModel* const model = owner.getModel(); | ||||
| if (model != 0) | if (model != 0) | ||||
| { | { | ||||
| const TableHeaderComponent* const header = owner.getHeader(); | |||||
| model->paintRowBackground (g, row, getWidth(), getHeight(), isSelected); | model->paintRowBackground (g, row, getWidth(), getHeight(), isSelected); | ||||
| const int numColumns = header->getNumColumns (true); | |||||
| const TableHeaderComponent& header = owner.getHeader(); | |||||
| const int numColumns = header.getNumColumns (true); | |||||
| for (int i = 0; i < numColumns; ++i) | for (int i = 0; i < numColumns; ++i) | ||||
| { | { | ||||
| if (! columnsWithComponents [i]) | |||||
| if (columnComponents[i] == 0) | |||||
| { | { | ||||
| const int columnId = header->getColumnIdOfIndex (i, true); | |||||
| Rectangle<int> columnRect (header->getColumnPosition (i)); | |||||
| columnRect.setSize (columnRect.getWidth(), getHeight()); | |||||
| const int columnId = header.getColumnIdOfIndex (i, true); | |||||
| const Rectangle<int> columnRect (header.getColumnPosition(i).withHeight (getHeight())); | |||||
| g.saveState(); | g.saveState(); | ||||
| g.reduceClipRegion (columnRect); | g.reduceClipRegion (columnRect); | ||||
| g.setOrigin (columnRect.getX(), 0); | g.setOrigin (columnRect.getX(), 0); | ||||
| model->paintCell (g, row, columnId, columnRect.getWidth(), columnRect.getHeight(), isSelected); | model->paintCell (g, row, columnId, columnRect.getWidth(), columnRect.getHeight(), isSelected); | ||||
| g.restoreState(); | g.restoreState(); | ||||
| } | } | ||||
| } | } | ||||
| @@ -89,79 +75,66 @@ public: | |||||
| void update (const int newRow, const bool isNowSelected) | void update (const int newRow, const bool isNowSelected) | ||||
| { | { | ||||
| jassert (newRow >= 0); | |||||
| if (newRow != row || isNowSelected != isSelected) | if (newRow != row || isNowSelected != isSelected) | ||||
| { | { | ||||
| row = newRow; | row = newRow; | ||||
| isSelected = isNowSelected; | isSelected = isNowSelected; | ||||
| repaint(); | repaint(); | ||||
| deleteAllChildren(); | |||||
| } | } | ||||
| if (row < owner.getNumRows()) | |||||
| { | |||||
| jassert (row >= 0); | |||||
| const Identifier tagPropertyName ("_tableLastUseNum"); | |||||
| const int newTag = Random::getSystemRandom().nextInt(); | |||||
| const TableHeaderComponent* const header = owner.getHeader(); | |||||
| const int numColumns = header->getNumColumns (true); | |||||
| TableListBoxModel* const model = owner.getModel(); | |||||
| columnsWithComponents.clear(); | |||||
| if (model != 0 && row < owner.getNumRows()) | |||||
| { | |||||
| const Identifier columnProperty ("_tableColumnId"); | |||||
| const int numColumns = owner.getHeader().getNumColumns (true); | |||||
| if (owner.getModel() != 0) | |||||
| for (int i = 0; i < numColumns; ++i) | |||||
| { | { | ||||
| for (int i = 0; i < numColumns; ++i) | |||||
| { | |||||
| const int columnId = header->getColumnIdOfIndex (i, true); | |||||
| const int columnId = owner.getHeader().getColumnIdOfIndex (i, true); | |||||
| Component* comp = columnComponents[i]; | |||||
| Component* const newComp | |||||
| = owner.getModel()->refreshComponentForCell (row, columnId, isSelected, | |||||
| findChildComponentForColumn (columnId)); | |||||
| if (comp != 0 && columnId != (int) comp->getProperties() [columnProperty]) | |||||
| { | |||||
| columnComponents.set (i, 0); | |||||
| comp = 0; | |||||
| } | |||||
| if (newComp != 0) | |||||
| { | |||||
| addAndMakeVisible (newComp); | |||||
| newComp->getProperties().set (tagPropertyName, newTag); | |||||
| newComp->getProperties().set (tableColumnPropertyTag, columnId); | |||||
| comp = model->refreshComponentForCell (row, columnId, isSelected, comp); | |||||
| columnComponents.set (i, comp); | |||||
| const Rectangle<int> columnRect (header->getColumnPosition (i)); | |||||
| newComp->setBounds (columnRect.getX(), 0, columnRect.getWidth(), getHeight()); | |||||
| if (comp != 0) | |||||
| { | |||||
| comp->getProperties().set (columnProperty, columnId); | |||||
| columnsWithComponents.setBit (i); | |||||
| } | |||||
| addAndMakeVisible (comp); | |||||
| resizeCustomComp (i); | |||||
| } | } | ||||
| } | } | ||||
| for (int i = getNumChildComponents(); --i >= 0;) | |||||
| { | |||||
| Component* const c = getChildComponent (i); | |||||
| if ((int) c->getProperties() [tagPropertyName] != newTag) | |||||
| delete c; | |||||
| } | |||||
| columnComponents.removeRange (numColumns, columnComponents.size()); | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| columnsWithComponents.clear(); | |||||
| deleteAllChildren(); | |||||
| columnComponents.clear(); | |||||
| } | } | ||||
| } | } | ||||
| void resized() | void resized() | ||||
| { | { | ||||
| for (int i = getNumChildComponents(); --i >= 0;) | |||||
| { | |||||
| Component* const c = getChildComponent (i); | |||||
| for (int i = columnComponents.size(); --i >= 0;) | |||||
| resizeCustomComp (i); | |||||
| } | |||||
| const int columnId = c->getProperties() [tableColumnPropertyTag]; | |||||
| void resizeCustomComp (const int index) | |||||
| { | |||||
| Component* const c = columnComponents.getUnchecked (index); | |||||
| if (columnId != 0) | |||||
| { | |||||
| const Rectangle<int> columnRect (owner.getHeader()->getColumnPosition (owner.getHeader()->getIndexOfColumnId (columnId, true))); | |||||
| c->setBounds (columnRect.getX(), 0, columnRect.getWidth(), getHeight()); | |||||
| } | |||||
| } | |||||
| if (c != 0) | |||||
| c->setBounds (owner.getHeader().getColumnPosition (index) | |||||
| .withY (0).withHeight (getHeight())); | |||||
| } | } | ||||
| void mouseDown (const MouseEvent& e) | void mouseDown (const MouseEvent& e) | ||||
| @@ -175,7 +148,7 @@ public: | |||||
| { | { | ||||
| owner.selectRowsBasedOnModifierKeys (row, e.mods); | owner.selectRowsBasedOnModifierKeys (row, e.mods); | ||||
| const int columnId = owner.getHeader()->getColumnIdAtX (e.x); | |||||
| const int columnId = owner.getHeader().getColumnIdAtX (e.x); | |||||
| if (columnId != 0 && owner.getModel() != 0) | if (columnId != 0 && owner.getModel() != 0) | ||||
| owner.getModel()->cellClicked (row, columnId, e); | owner.getModel()->cellClicked (row, columnId, e); | ||||
| @@ -212,7 +185,7 @@ public: | |||||
| { | { | ||||
| owner.selectRowsBasedOnModifierKeys (row, e.mods); | owner.selectRowsBasedOnModifierKeys (row, e.mods); | ||||
| const int columnId = owner.getHeader()->getColumnIdAtX (e.x); | |||||
| const int columnId = owner.getHeader().getColumnIdAtX (e.x); | |||||
| if (columnId != 0 && owner.getModel() != 0) | if (columnId != 0 && owner.getModel() != 0) | ||||
| owner.getModel()->cellClicked (row, columnId, e); | owner.getModel()->cellClicked (row, columnId, e); | ||||
| @@ -221,7 +194,7 @@ public: | |||||
| void mouseDoubleClick (const MouseEvent& e) | void mouseDoubleClick (const MouseEvent& e) | ||||
| { | { | ||||
| const int columnId = owner.getHeader()->getColumnIdAtX (e.x); | |||||
| const int columnId = owner.getHeader().getColumnIdAtX (e.x); | |||||
| if (columnId != 0 && owner.getModel() != 0) | if (columnId != 0 && owner.getModel() != 0) | ||||
| owner.getModel()->cellDoubleClicked (row, columnId, e); | owner.getModel()->cellDoubleClicked (row, columnId, e); | ||||
| @@ -229,7 +202,7 @@ public: | |||||
| const String getTooltip() | const String getTooltip() | ||||
| { | { | ||||
| const int columnId = owner.getHeader()->getColumnIdAtX (getMouseXYRelative().getX()); | |||||
| const int columnId = owner.getHeader().getColumnIdAtX (getMouseXYRelative().getX()); | |||||
| if (columnId != 0 && owner.getModel() != 0) | if (columnId != 0 && owner.getModel() != 0) | ||||
| return owner.getModel()->getCellTooltip (row, columnId); | return owner.getModel()->getCellTooltip (row, columnId); | ||||
| @@ -239,24 +212,16 @@ public: | |||||
| Component* findChildComponentForColumn (const int columnId) const | Component* findChildComponentForColumn (const int columnId) const | ||||
| { | { | ||||
| for (int i = getNumChildComponents(); --i >= 0;) | |||||
| { | |||||
| Component* const c = getChildComponent (i); | |||||
| if ((int) c->getProperties() [tableColumnPropertyTag] == columnId) | |||||
| return c; | |||||
| } | |||||
| return 0; | |||||
| return columnComponents [owner.getHeader().getIndexOfColumnId (columnId, true)]; | |||||
| } | } | ||||
| juce_UseDebuggingNewOperator | juce_UseDebuggingNewOperator | ||||
| private: | private: | ||||
| TableListBox& owner; | TableListBox& owner; | ||||
| OwnedArray<Component> columnComponents; | |||||
| int row; | int row; | ||||
| bool isSelected, isDragging, selectRowOnMouseUp; | bool isSelected, isDragging, selectRowOnMouseUp; | ||||
| BigInteger columnsWithComponents; | |||||
| TableListRowComp (const TableListRowComp&); | TableListRowComp (const TableListRowComp&); | ||||
| TableListRowComp& operator= (const TableListRowComp&); | TableListRowComp& operator= (const TableListRowComp&); | ||||
| @@ -277,7 +242,7 @@ public: | |||||
| if (owner.isAutoSizeMenuOptionShown()) | if (owner.isAutoSizeMenuOptionShown()) | ||||
| { | { | ||||
| menu.addItem (autoSizeColumnId, TRANS("Auto-size this column"), columnIdClicked != 0); | menu.addItem (autoSizeColumnId, TRANS("Auto-size this column"), columnIdClicked != 0); | ||||
| menu.addItem (autoSizeAllId, TRANS("Auto-size all columns"), owner.getHeader()->getNumColumns (true) > 0); | |||||
| menu.addItem (autoSizeAllId, TRANS("Auto-size all columns"), owner.getHeader().getNumColumns (true) > 0); | |||||
| menu.addSeparator(); | menu.addSeparator(); | ||||
| } | } | ||||
| @@ -286,17 +251,11 @@ public: | |||||
| void reactToMenuItem (int menuReturnId, int columnIdClicked) | void reactToMenuItem (int menuReturnId, int columnIdClicked) | ||||
| { | { | ||||
| if (menuReturnId == autoSizeColumnId) | |||||
| switch (menuReturnId) | |||||
| { | { | ||||
| owner.autoSizeColumn (columnIdClicked); | |||||
| } | |||||
| else if (menuReturnId == autoSizeAllId) | |||||
| { | |||||
| owner.autoSizeAllColumns(); | |||||
| } | |||||
| else | |||||
| { | |||||
| TableHeaderComponent::reactToMenuItem (menuReturnId, columnIdClicked); | |||||
| case autoSizeColumnId: owner.autoSizeColumn (columnIdClicked); break; | |||||
| case autoSizeAllId: owner.autoSizeAllColumns(); break; | |||||
| default: TableHeaderComponent::reactToMenuItem (menuReturnId, columnIdClicked); break; | |||||
| } | } | ||||
| } | } | ||||
| @@ -375,8 +334,7 @@ bool TableListBox::isAutoSizeMenuOptionShown() const | |||||
| return autoSizeOptionsShown; | return autoSizeOptionsShown; | ||||
| } | } | ||||
| const Rectangle<int> TableListBox::getCellPosition (const int columnId, | |||||
| const int rowNumber, | |||||
| const Rectangle<int> TableListBox::getCellPosition (const int columnId, const int rowNumber, | |||||
| const bool relativeToComponentTopLeft) const | const bool relativeToComponentTopLeft) const | ||||
| { | { | ||||
| Rectangle<int> headerCell (header->getColumnPosition (header->getIndexOfColumnId (columnId, true))); | Rectangle<int> headerCell (header->getColumnPosition (header->getIndexOfColumnId (columnId, true))); | ||||
| @@ -384,10 +342,9 @@ const Rectangle<int> TableListBox::getCellPosition (const int columnId, | |||||
| if (relativeToComponentTopLeft) | if (relativeToComponentTopLeft) | ||||
| headerCell.translate (header->getX(), 0); | headerCell.translate (header->getX(), 0); | ||||
| const Rectangle<int> row (getRowPosition (rowNumber, relativeToComponentTopLeft)); | |||||
| return Rectangle<int> (headerCell.getX(), row.getY(), | |||||
| headerCell.getWidth(), row.getHeight()); | |||||
| return getRowPosition (rowNumber, relativeToComponentTopLeft) | |||||
| .withX (headerCell.getX()) | |||||
| .withWidth (headerCell.getWidth()); | |||||
| } | } | ||||
| Component* TableListBox::getCellComponent (int columnId, int rowNumber) const | Component* TableListBox::getCellComponent (int columnId, int rowNumber) const | ||||
| @@ -514,52 +471,18 @@ void TableListBox::updateColumnComponents() const | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| void TableListBoxModel::cellClicked (int, int, const MouseEvent&) | |||||
| { | |||||
| } | |||||
| void TableListBoxModel::cellDoubleClicked (int, int, const MouseEvent&) | |||||
| { | |||||
| } | |||||
| void TableListBoxModel::backgroundClicked() | |||||
| { | |||||
| } | |||||
| void TableListBoxModel::sortOrderChanged (int, const bool) | |||||
| { | |||||
| } | |||||
| int TableListBoxModel::getColumnAutoSizeWidth (int) | |||||
| { | |||||
| return 0; | |||||
| } | |||||
| void TableListBoxModel::selectedRowsChanged (int) | |||||
| { | |||||
| } | |||||
| void TableListBoxModel::deleteKeyPressed (int) | |||||
| { | |||||
| } | |||||
| void TableListBoxModel::returnKeyPressed (int) | |||||
| { | |||||
| } | |||||
| void TableListBoxModel::listWasScrolled() | |||||
| { | |||||
| } | |||||
| const String TableListBoxModel::getCellTooltip (int /*rowNumber*/, int /*columnId*/) | |||||
| { | |||||
| return String::empty; | |||||
| } | |||||
| const String TableListBoxModel::getDragSourceDescription (const SparseSet<int>&) | |||||
| { | |||||
| return String::empty; | |||||
| } | |||||
| void TableListBoxModel::cellClicked (int, int, const MouseEvent&) {} | |||||
| void TableListBoxModel::cellDoubleClicked (int, int, const MouseEvent&) {} | |||||
| void TableListBoxModel::backgroundClicked() {} | |||||
| void TableListBoxModel::sortOrderChanged (int, const bool) {} | |||||
| int TableListBoxModel::getColumnAutoSizeWidth (int) { return 0; } | |||||
| void TableListBoxModel::selectedRowsChanged (int) {} | |||||
| void TableListBoxModel::deleteKeyPressed (int) {} | |||||
| void TableListBoxModel::returnKeyPressed (int) {} | |||||
| void TableListBoxModel::listWasScrolled() {} | |||||
| const String TableListBoxModel::getCellTooltip (int /*rowNumber*/, int /*columnId*/) { return String::empty; } | |||||
| const String TableListBoxModel::getDragSourceDescription (const SparseSet<int>&) { return String::empty; } | |||||
| Component* TableListBoxModel::refreshComponentForCell (int, int, bool, Component* existingComponentToUpdate) | Component* TableListBoxModel::refreshComponentForCell (int, int, bool, Component* existingComponentToUpdate) | ||||
| { | { | ||||
| @@ -208,8 +208,8 @@ public: | |||||
| The model pointer passed-in can be null, in which case you can set it later | The model pointer passed-in can be null, in which case you can set it later | ||||
| with setModel(). | with setModel(). | ||||
| */ | */ | ||||
| TableListBox (const String& componentName, | |||||
| TableListBoxModel* model); | |||||
| TableListBox (const String& componentName = String::empty, | |||||
| TableListBoxModel* model = 0); | |||||
| /** Destructor. */ | /** Destructor. */ | ||||
| ~TableListBox(); | ~TableListBox(); | ||||
| @@ -224,7 +224,7 @@ public: | |||||
| //============================================================================== | //============================================================================== | ||||
| /** Returns the header component being used in this table. */ | /** Returns the header component being used in this table. */ | ||||
| TableHeaderComponent* getHeader() const { return header; } | |||||
| TableHeaderComponent& getHeader() const { return *header; } | |||||
| /** Changes the height of the table header component. | /** Changes the height of the table header component. | ||||
| @see getHeaderHeight | @see getHeaderHeight | ||||
| @@ -281,7 +281,7 @@ Toolbar::Toolbar() | |||||
| Toolbar::~Toolbar() | Toolbar::~Toolbar() | ||||
| { | { | ||||
| deleteAllChildren(); | |||||
| items.clear(); | |||||
| } | } | ||||
| void Toolbar::setVertical (const bool shouldBeVertical) | void Toolbar::setVertical (const bool shouldBeVertical) | ||||
| @@ -295,13 +295,7 @@ void Toolbar::setVertical (const bool shouldBeVertical) | |||||
| void Toolbar::clear() | void Toolbar::clear() | ||||
| { | { | ||||
| for (int i = items.size(); --i >= 0;) | |||||
| { | |||||
| ToolbarItemComponent* const tc = items.getUnchecked(i); | |||||
| items.remove (i); | |||||
| delete tc; | |||||
| } | |||||
| items.clear(); | |||||
| resized(); | resized(); | ||||
| } | } | ||||
| @@ -365,14 +359,8 @@ void Toolbar::addDefaultItems (ToolbarItemFactory& factoryToUse) | |||||
| void Toolbar::removeToolbarItem (const int itemIndex) | void Toolbar::removeToolbarItem (const int itemIndex) | ||||
| { | { | ||||
| ToolbarItemComponent* const tc = getItemComponent (itemIndex); | |||||
| if (tc != 0) | |||||
| { | |||||
| items.removeValue (tc); | |||||
| delete tc; | |||||
| resized(); | |||||
| } | |||||
| items.remove (itemIndex); | |||||
| resized(); | |||||
| } | } | ||||
| int Toolbar::getNumItems() const throw() | int Toolbar::getNumItems() const throw() | ||||
| @@ -672,7 +660,7 @@ void Toolbar::itemDragMove (const String&, Component* sourceComponent, int x, in | |||||
| if (newIndex != currentIndex) | if (newIndex != currentIndex) | ||||
| { | { | ||||
| items.removeValue (tc); | |||||
| items.removeObject (tc, false); | |||||
| removeChildComponent (tc); | removeChildComponent (tc); | ||||
| addChildComponent (tc, newIndex); | addChildComponent (tc, newIndex); | ||||
| items.insert (newIndex, tc); | items.insert (newIndex, tc); | ||||
| @@ -695,7 +683,7 @@ void Toolbar::itemDragExit (const String&, Component* sourceComponent) | |||||
| { | { | ||||
| if (isParentOf (tc)) | if (isParentOf (tc)) | ||||
| { | { | ||||
| items.removeValue (tc); | |||||
| items.removeObject (tc, false); | |||||
| removeChildComponent (tc); | removeChildComponent (tc); | ||||
| updateAllItemPositions (true); | updateAllItemPositions (true); | ||||
| } | } | ||||
| @@ -294,12 +294,12 @@ public: | |||||
| juce_UseDebuggingNewOperator | juce_UseDebuggingNewOperator | ||||
| private: | private: | ||||
| Button* missingItemsButton; | |||||
| ScopedPointer<Button> missingItemsButton; | |||||
| bool vertical, isEditingActive; | bool vertical, isEditingActive; | ||||
| ToolbarItemStyle toolbarStyle; | ToolbarItemStyle toolbarStyle; | ||||
| class MissingItemsComponent; | class MissingItemsComponent; | ||||
| friend class MissingItemsComponent; | friend class MissingItemsComponent; | ||||
| Array <ToolbarItemComponent*> items; | |||||
| OwnedArray <ToolbarItemComponent> items; | |||||
| friend class ItemDragAndDropOverlayComponent; | friend class ItemDragAndDropOverlayComponent; | ||||
| static const char* const toolbarDragDescriptor; | static const char* const toolbarDragDescriptor; | ||||
| @@ -786,36 +786,43 @@ const Rectangle<int> Component::getScreenBounds() const | |||||
| namespace CoordinateHelpers | namespace CoordinateHelpers | ||||
| { | { | ||||
| const Point<int> convertFromParentSpace (const Component* comp, const Point<int>& pointInParentSpace) | |||||
| inline bool hitTest (Component& comp, const Point<int>& localPoint) | |||||
| { | { | ||||
| return pointInParentSpace - comp->getPosition(); | |||||
| return ((unsigned int) localPoint.getX()) < (unsigned int) comp.getWidth() | |||||
| && ((unsigned int) localPoint.getY()) < (unsigned int) comp.getHeight() | |||||
| && comp.hitTest (localPoint.getX(), localPoint.getY()); | |||||
| } | } | ||||
| const Rectangle<int> convertFromParentSpace (const Component* comp, const Rectangle<int>& areaInParentSpace) | |||||
| const Point<int> convertFromParentSpace (const Component& comp, const Point<int>& pointInParentSpace) | |||||
| { | { | ||||
| return areaInParentSpace - comp->getPosition(); | |||||
| return pointInParentSpace - comp.getPosition(); | |||||
| } | } | ||||
| const Point<int> convertToParentSpace (const Component* comp, const Point<int>& pointInLocalSpace) | |||||
| const Rectangle<int> convertFromParentSpace (const Component& comp, const Rectangle<int>& areaInParentSpace) | |||||
| { | { | ||||
| return pointInLocalSpace + comp->getPosition(); | |||||
| return areaInParentSpace - comp.getPosition(); | |||||
| } | } | ||||
| const Rectangle<int> convertToParentSpace (const Component* comp, const Rectangle<int>& areaInLocalSpace) | |||||
| const Point<int> convertToParentSpace (const Component& comp, const Point<int>& pointInLocalSpace) | |||||
| { | { | ||||
| return areaInLocalSpace + comp->getPosition(); | |||||
| return pointInLocalSpace + comp.getPosition(); | |||||
| } | |||||
| const Rectangle<int> convertToParentSpace (const Component& comp, const Rectangle<int>& areaInLocalSpace) | |||||
| { | |||||
| return areaInLocalSpace + comp.getPosition(); | |||||
| } | } | ||||
| template <typename Type> | template <typename Type> | ||||
| const Type convertFromDistantParentSpace (const Component* parent, const Component* target, Type coordInParent) | |||||
| const Type convertFromDistantParentSpace (const Component* parent, const Component& target, Type coordInParent) | |||||
| { | { | ||||
| const Component* const directParent = target->getParentComponent(); | |||||
| const Component* const directParent = target.getParentComponent(); | |||||
| jassert (directParent != 0); | jassert (directParent != 0); | ||||
| if (directParent == parent) | if (directParent == parent) | ||||
| return convertFromParentSpace (target, coordInParent); | return convertFromParentSpace (target, coordInParent); | ||||
| return convertFromParentSpace (target, convertFromDistantParentSpace (parent, directParent, coordInParent)); | |||||
| return convertFromParentSpace (target, convertFromDistantParentSpace (parent, *directParent, coordInParent)); | |||||
| } | } | ||||
| template <typename Type> | template <typename Type> | ||||
| @@ -827,7 +834,7 @@ namespace CoordinateHelpers | |||||
| return p; | return p; | ||||
| if (source->isParentOf (target)) | if (source->isParentOf (target)) | ||||
| return convertFromDistantParentSpace (source, target, p); | |||||
| return convertFromDistantParentSpace (source, *target, p); | |||||
| if (source->isOnDesktop()) | if (source->isOnDesktop()) | ||||
| { | { | ||||
| @@ -836,7 +843,7 @@ namespace CoordinateHelpers | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| p = convertToParentSpace (source, p); | |||||
| p = convertToParentSpace (*source, p); | |||||
| source = source->getParentComponent(); | source = source->getParentComponent(); | ||||
| } | } | ||||
| } | } | ||||
| @@ -850,12 +857,24 @@ namespace CoordinateHelpers | |||||
| if (topLevelComp->isOnDesktop()) | if (topLevelComp->isOnDesktop()) | ||||
| p = topLevelComp->getPeer()->globalToLocal (p); | p = topLevelComp->getPeer()->globalToLocal (p); | ||||
| else | else | ||||
| p = convertFromParentSpace (topLevelComp, p); | |||||
| p = convertFromParentSpace (*topLevelComp, p); | |||||
| if (topLevelComp == target) | if (topLevelComp == target) | ||||
| return p; | return p; | ||||
| return convertFromDistantParentSpace (topLevelComp, target, p); | |||||
| return convertFromDistantParentSpace (topLevelComp, *target, p); | |||||
| } | |||||
| const Rectangle<int> getUnclippedArea (const Component& comp) | |||||
| { | |||||
| Rectangle<int> r (comp.getLocalBounds()); | |||||
| Component* const p = comp.getParentComponent(); | |||||
| if (p != 0) | |||||
| r = r.getIntersection (convertFromParentSpace (comp, getUnclippedArea (*p))); | |||||
| return r; | |||||
| } | } | ||||
| } | } | ||||
| @@ -1100,15 +1119,11 @@ bool Component::hitTest (int x, int y) | |||||
| { | { | ||||
| for (int i = getNumChildComponents(); --i >= 0;) | for (int i = getNumChildComponents(); --i >= 0;) | ||||
| { | { | ||||
| Component* const c = getChildComponent (i); | |||||
| Component& child = *getChildComponent (i); | |||||
| if (c->isVisible() | |||||
| && c->bounds_.contains (x, y) | |||||
| && c->hitTest (x - c->getX(), | |||||
| y - c->getY())) | |||||
| { | |||||
| if (child.isVisible() | |||||
| && CoordinateHelpers::hitTest (child, CoordinateHelpers::convertFromParentSpace (child, Point<int> (x, y)))) | |||||
| return true; | return true; | ||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -1129,70 +1144,50 @@ void Component::getInterceptsMouseClicks (bool& allowsClicksOnThisComponent, | |||||
| allowsClicksOnChildComponents = flags.allowChildMouseClicksFlag; | allowsClicksOnChildComponents = flags.allowChildMouseClicksFlag; | ||||
| } | } | ||||
| bool Component::contains (const int x, const int y) | |||||
| bool Component::contains (const Point<int>& point) | |||||
| { | { | ||||
| if (((unsigned int) x) < (unsigned int) getWidth() | |||||
| && ((unsigned int) y) < (unsigned int) getHeight() | |||||
| && hitTest (x, y)) | |||||
| if (CoordinateHelpers::hitTest (*this, point)) | |||||
| { | { | ||||
| if (parentComponent_ != 0) | if (parentComponent_ != 0) | ||||
| { | { | ||||
| return parentComponent_->contains (x + getX(), | |||||
| y + getY()); | |||||
| return parentComponent_->contains (CoordinateHelpers::convertToParentSpace (*this, point)); | |||||
| } | } | ||||
| else if (flags.hasHeavyweightPeerFlag) | else if (flags.hasHeavyweightPeerFlag) | ||||
| { | { | ||||
| const ComponentPeer* const peer = getPeer(); | const ComponentPeer* const peer = getPeer(); | ||||
| if (peer != 0) | if (peer != 0) | ||||
| return peer->contains (Point<int> (x, y), true); | |||||
| return peer->contains (point, true); | |||||
| } | } | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| bool Component::reallyContains (int x, int y, const bool returnTrueIfWithinAChild) | |||||
| bool Component::reallyContains (const int x, const int y, const bool returnTrueIfWithinAChild) | |||||
| { | { | ||||
| if (! contains (x, y)) | |||||
| return false; | |||||
| const Point<int> p (x, y); | |||||
| Component* p = this; | |||||
| while (p->parentComponent_ != 0) | |||||
| { | |||||
| x += p->getX(); | |||||
| y += p->getY(); | |||||
| p = p->parentComponent_; | |||||
| } | |||||
| if (! contains (p)) | |||||
| return false; | |||||
| const Component* const c = p->getComponentAt (x, y); | |||||
| Component* const top = getTopLevelComponent(); | |||||
| const Component* const compAtPosition = top->getComponentAt (top->getLocalPoint (this, p)); | |||||
| return (c == this) || (returnTrueIfWithinAChild && isParentOf (c)); | |||||
| return (compAtPosition == this) || (returnTrueIfWithinAChild && isParentOf (compAtPosition)); | |||||
| } | } | ||||
| Component* Component::getComponentAt (const Point<int>& position) | Component* Component::getComponentAt (const Point<int>& position) | ||||
| { | { | ||||
| return getComponentAt (position.getX(), position.getY()); | |||||
| } | |||||
| Component* Component::getComponentAt (const int x, const int y) | |||||
| { | |||||
| if (flags.visibleFlag | |||||
| && ((unsigned int) x) < (unsigned int) getWidth() | |||||
| && ((unsigned int) y) < (unsigned int) getHeight() | |||||
| && hitTest (x, y)) | |||||
| if (flags.visibleFlag && CoordinateHelpers::hitTest (*this, position)) | |||||
| { | { | ||||
| for (int i = childComponentList_.size(); --i >= 0;) | for (int i = childComponentList_.size(); --i >= 0;) | ||||
| { | { | ||||
| Component* const child = childComponentList_.getUnchecked(i); | |||||
| Component* child = childComponentList_.getUnchecked(i); | |||||
| child = child->getComponentAt (CoordinateHelpers::convertFromParentSpace (*child, position)); | |||||
| Component* const c = child->getComponentAt (x - child->getX(), | |||||
| y - child->getY()); | |||||
| if (c != 0) | |||||
| return c; | |||||
| if (child != 0) | |||||
| return child; | |||||
| } | } | ||||
| return this; | return this; | ||||
| @@ -1201,6 +1196,11 @@ Component* Component::getComponentAt (const int x, const int y) | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| Component* Component::getComponentAt (const int x, const int y) | |||||
| { | |||||
| return getComponentAt (Point<int> (x, y)); | |||||
| } | |||||
| //============================================================================== | //============================================================================== | ||||
| void Component::addChildComponent (Component* const child, int zOrder) | void Component::addChildComponent (Component* const child, int zOrder) | ||||
| { | { | ||||
| @@ -1925,27 +1925,6 @@ const Rectangle<int> Component::getParentOrMainMonitorBounds() const | |||||
| : Desktop::getInstance().getMainMonitorArea(); | : Desktop::getInstance().getMainMonitorArea(); | ||||
| } | } | ||||
| const Rectangle<int> Component::getUnclippedArea() const | |||||
| { | |||||
| int x = 0, y = 0, w = getWidth(), h = getHeight(); | |||||
| Component* p = parentComponent_; | |||||
| int px = getX(); | |||||
| int py = getY(); | |||||
| while (p != 0) | |||||
| { | |||||
| if (! Rectangle<int>::intersectRectangles (x, y, w, h, -px, -py, p->getWidth(), p->getHeight())) | |||||
| return Rectangle<int>(); | |||||
| px += p->getX(); | |||||
| py += p->getY(); | |||||
| p = p->parentComponent_; | |||||
| } | |||||
| return Rectangle<int> (x, y, w, h); | |||||
| } | |||||
| void Component::clipObscuredRegions (Graphics& g, const Rectangle<int>& clipRect, | void Component::clipObscuredRegions (Graphics& g, const Rectangle<int>& clipRect, | ||||
| const int deltaX, const int deltaY) const | const int deltaX, const int deltaY) const | ||||
| { | { | ||||
| @@ -1977,7 +1956,7 @@ void Component::clipObscuredRegions (Graphics& g, const Rectangle<int>& clipRect | |||||
| void Component::getVisibleArea (RectangleList& result, const bool includeSiblings) const | void Component::getVisibleArea (RectangleList& result, const bool includeSiblings) const | ||||
| { | { | ||||
| result.clear(); | result.clear(); | ||||
| const Rectangle<int> unclipped (getUnclippedArea()); | |||||
| const Rectangle<int> unclipped (CoordinateHelpers::getUnclippedArea (*this)); | |||||
| if (! unclipped.isEmpty()) | if (! unclipped.isEmpty()) | ||||
| { | { | ||||
| @@ -728,15 +728,14 @@ public: | |||||
| Never override this method! Use hitTest to create custom hit regions. | Never override this method! Use hitTest to create custom hit regions. | ||||
| @param x the x co-ordinate to test, relative to this component's left hand edge. | |||||
| @param y the y co-ordinate to test, relative to this component's top edge. | |||||
| @param point the x co-ordinate to test, relative to this component's top-left. | |||||
| @returns true if the point is within the component's hit-test area, but only if | @returns true if the point is within the component's hit-test area, but only if | ||||
| that part of the component isn't clipped by its parent component. Note | that part of the component isn't clipped by its parent component. Note | ||||
| that this won't take into account any overlapping sibling components | that this won't take into account any overlapping sibling components | ||||
| which might be in the way - for that, see reallyContains() | which might be in the way - for that, see reallyContains() | ||||
| @see hitTest, reallyContains, getComponentAt | @see hitTest, reallyContains, getComponentAt | ||||
| */ | */ | ||||
| virtual bool contains (int x, int y); | |||||
| bool contains (const Point<int>& point); | |||||
| /** Returns true if a given point lies in this component, taking any overlapping | /** Returns true if a given point lies in this component, taking any overlapping | ||||
| siblings into account. | siblings into account. | ||||
| @@ -1949,6 +1948,9 @@ public: | |||||
| /** If the component is valid, this deletes it and sets this pointer to null. */ | /** If the component is valid, this deletes it and sets this pointer to null. */ | ||||
| void deleteAndZero() { delete comp; jassert (comp == 0); } | void deleteAndZero() { delete comp; jassert (comp == 0); } | ||||
| bool operator== (ComponentType* component) const throw() { return comp == component; } | |||||
| bool operator!= (ComponentType* component) const throw() { return comp != component; } | |||||
| //============================================================================== | //============================================================================== | ||||
| juce_UseDebuggingNewOperator | juce_UseDebuggingNewOperator | ||||
| @@ -2097,8 +2099,6 @@ private: | |||||
| const Rectangle<int>& clipRect, const Component* const compToAvoid) const; | const Rectangle<int>& clipRect, const Component* const compToAvoid) const; | ||||
| void clipObscuredRegions (Graphics& g, const Rectangle<int>& clipRect, int deltaX, int deltaY) const; | void clipObscuredRegions (Graphics& g, const Rectangle<int>& clipRect, int deltaX, int deltaY) const; | ||||
| // how much of the component is not off the edges of its parents | |||||
| const Rectangle<int> getUnclippedArea() const; | |||||
| void sendVisibilityChangeMessage(); | void sendVisibilityChangeMessage(); | ||||
| const Rectangle<int> getParentOrMainMonitorBounds() const; | const Rectangle<int> getParentOrMainMonitorBounds() const; | ||||
| @@ -2109,9 +2109,14 @@ private: | |||||
| // implement its methods instead of this Component method). | // implement its methods instead of this Component method). | ||||
| virtual void filesDropped (const StringArray&, int, int) {} | virtual void filesDropped (const StringArray&, int, int) {} | ||||
| // components aren't allowed to have copy constructors, as this would mess up parent | |||||
| // hierarchies. You might need to give your subclasses a private dummy constructor like | |||||
| // this one to avoid compiler warnings. | |||||
| // This is included here to cause an error if you use or overload it - it has been deprecated in | |||||
| // favour of contains (const Point<int>&) | |||||
| void contains (int, int); | |||||
| /* Components aren't allowed to have copy constructors, as this would mess up parent hierarchies. | |||||
| You might need to give your subclasses a private dummy constructor like this one to avoid | |||||
| compiler warnings. | |||||
| */ | |||||
| Component (const Component&); | Component (const Component&); | ||||
| Component& operator= (const Component&); | Component& operator= (const Component&); | ||||
| @@ -162,8 +162,8 @@ Component* Desktop::findComponentAt (const Point<int>& screenPosition) const | |||||
| { | { | ||||
| const Point<int> relative (c->getLocalPoint (0, screenPosition)); | const Point<int> relative (c->getLocalPoint (0, screenPosition)); | ||||
| if (c->contains (relative.getX(), relative.getY())) | |||||
| return c->getComponentAt (relative.getX(), relative.getY()); | |||||
| if (c->contains (relative)) | |||||
| return c->getComponentAt (relative); | |||||
| } | } | ||||
| } | } | ||||
| @@ -40,13 +40,13 @@ BEGIN_JUCE_NAMESPACE | |||||
| //============================================================================== | //============================================================================== | ||||
| class KeyMappingChangeButton : public Button | |||||
| class KeyMappingEditorComponent::ChangeKeyButton : public Button | |||||
| { | { | ||||
| public: | public: | ||||
| KeyMappingChangeButton (KeyMappingEditorComponent& owner_, | |||||
| const CommandID commandID_, | |||||
| const String& keyName, | |||||
| const int keyNum_) | |||||
| ChangeKeyButton (KeyMappingEditorComponent& owner_, | |||||
| const CommandID commandID_, | |||||
| const String& keyName, | |||||
| const int keyNum_) | |||||
| : Button (keyName), | : Button (keyName), | ||||
| owner (owner_), | owner (owner_), | ||||
| commandID (commandID_), | commandID (commandID_), | ||||
| @@ -75,21 +75,16 @@ public: | |||||
| m.addSeparator(); | m.addSeparator(); | ||||
| m.addItem (2, TRANS("remove this key-mapping")); | m.addItem (2, TRANS("remove this key-mapping")); | ||||
| const int res = m.show(); | |||||
| if (res == 1) | |||||
| { | |||||
| owner.assignNewKey (commandID, keyNum); | |||||
| } | |||||
| else if (res == 2) | |||||
| switch (m.show()) | |||||
| { | { | ||||
| owner.getMappings()->removeKeyPress (commandID, keyNum); | |||||
| case 1: assignNewKey(); break; | |||||
| case 2: owner.getMappings().removeKeyPress (commandID, keyNum); break; | |||||
| default: break; | |||||
| } | } | ||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| // + button pressed.. | |||||
| owner.assignNewKey (commandID, -1); | |||||
| assignNewKey(); // + button pressed.. | |||||
| } | } | ||||
| } | } | ||||
| @@ -106,6 +101,88 @@ public: | |||||
| } | } | ||||
| } | } | ||||
| //============================================================================== | |||||
| class KeyEntryWindow : public AlertWindow | |||||
| { | |||||
| public: | |||||
| KeyEntryWindow (KeyMappingEditorComponent& owner_) | |||||
| : AlertWindow (TRANS("New key-mapping"), | |||||
| TRANS("Please press a key combination now..."), | |||||
| AlertWindow::NoIcon), | |||||
| owner (owner_) | |||||
| { | |||||
| addButton (TRANS("Ok"), 1); | |||||
| addButton (TRANS("Cancel"), 0); | |||||
| // (avoid return + escape keys getting processed by the buttons..) | |||||
| for (int i = getNumChildComponents(); --i >= 0;) | |||||
| getChildComponent (i)->setWantsKeyboardFocus (false); | |||||
| setWantsKeyboardFocus (true); | |||||
| grabKeyboardFocus(); | |||||
| } | |||||
| bool keyPressed (const KeyPress& key) | |||||
| { | |||||
| lastPress = key; | |||||
| String message (TRANS("Key: ") + owner.getDescriptionForKeyPress (key)); | |||||
| const CommandID previousCommand = owner.getMappings().findCommandForKeyPress (key); | |||||
| if (previousCommand != 0) | |||||
| message << "\n\n" << TRANS("(Currently assigned to \"") | |||||
| << owner.getMappings().getCommandManager()->getNameOfCommand (previousCommand) << "\")"; | |||||
| setMessage (message); | |||||
| return true; | |||||
| } | |||||
| bool keyStateChanged (bool) | |||||
| { | |||||
| return true; | |||||
| } | |||||
| KeyPress lastPress; | |||||
| private: | |||||
| KeyMappingEditorComponent& owner; | |||||
| KeyEntryWindow (const KeyEntryWindow&); | |||||
| KeyEntryWindow& operator= (const KeyEntryWindow&); | |||||
| }; | |||||
| void assignNewKey() | |||||
| { | |||||
| KeyEntryWindow entryWindow (owner); | |||||
| if (entryWindow.runModalLoop() != 0) | |||||
| { | |||||
| entryWindow.setVisible (false); | |||||
| if (entryWindow.lastPress.isValid()) | |||||
| { | |||||
| const CommandID previousCommand = owner.getMappings().findCommandForKeyPress (entryWindow.lastPress); | |||||
| if (previousCommand == 0 | |||||
| || AlertWindow::showOkCancelBox (AlertWindow::WarningIcon, | |||||
| TRANS("Change key-mapping"), | |||||
| TRANS("This key is already assigned to the command \"") | |||||
| + owner.getMappings().getCommandManager()->getNameOfCommand (previousCommand) | |||||
| + TRANS("\"\n\nDo you want to re-assign it to this new command instead?"), | |||||
| TRANS("Re-assign"), | |||||
| TRANS("Cancel"))) | |||||
| { | |||||
| owner.getMappings().removeKeyPress (entryWindow.lastPress); | |||||
| if (keyNum >= 0) | |||||
| owner.getMappings().removeKeyPress (commandID, keyNum); | |||||
| owner.getMappings().addKeyPress (commandID, entryWindow.lastPress, keyNum); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| juce_UseDebuggingNewOperator | juce_UseDebuggingNewOperator | ||||
| private: | private: | ||||
| @@ -113,43 +190,37 @@ private: | |||||
| const CommandID commandID; | const CommandID commandID; | ||||
| const int keyNum; | const int keyNum; | ||||
| KeyMappingChangeButton (const KeyMappingChangeButton&); | |||||
| KeyMappingChangeButton& operator= (const KeyMappingChangeButton&); | |||||
| ChangeKeyButton (const ChangeKeyButton&); | |||||
| ChangeKeyButton& operator= (const ChangeKeyButton&); | |||||
| }; | }; | ||||
| //============================================================================== | //============================================================================== | ||||
| class KeyMappingItemComponent : public Component | |||||
| class KeyMappingEditorComponent::ItemComponent : public Component | |||||
| { | { | ||||
| public: | public: | ||||
| KeyMappingItemComponent (KeyMappingEditorComponent& owner_, const CommandID commandID_) | |||||
| ItemComponent (KeyMappingEditorComponent& owner_, const CommandID commandID_) | |||||
| : owner (owner_), commandID (commandID_) | : owner (owner_), commandID (commandID_) | ||||
| { | { | ||||
| setInterceptsMouseClicks (false, true); | setInterceptsMouseClicks (false, true); | ||||
| const bool isReadOnly = owner.isCommandReadOnly (commandID); | const bool isReadOnly = owner.isCommandReadOnly (commandID); | ||||
| const Array <KeyPress> keyPresses (owner.getMappings()->getKeyPressesAssignedToCommand (commandID)); | |||||
| const Array <KeyPress> keyPresses (owner.getMappings().getKeyPressesAssignedToCommand (commandID)); | |||||
| for (int i = 0; i < jmin ((int) maxNumAssignments, keyPresses.size()); ++i) | for (int i = 0; i < jmin ((int) maxNumAssignments, keyPresses.size()); ++i) | ||||
| { | |||||
| KeyMappingChangeButton* const kb | |||||
| = new KeyMappingChangeButton (owner, commandID, | |||||
| owner.getDescriptionForKeyPress (keyPresses.getReference (i)), i); | |||||
| kb->setEnabled (! isReadOnly); | |||||
| addAndMakeVisible (kb); | |||||
| } | |||||
| addKeyPressButton (owner.getDescriptionForKeyPress (keyPresses.getReference (i)), i, isReadOnly); | |||||
| KeyMappingChangeButton* const kb | |||||
| = new KeyMappingChangeButton (owner, commandID, String::empty, -1); | |||||
| addChildComponent (kb); | |||||
| kb->setVisible (keyPresses.size() < (int) maxNumAssignments && ! isReadOnly); | |||||
| addKeyPressButton (String::empty, -1, isReadOnly); | |||||
| } | } | ||||
| ~KeyMappingItemComponent() | |||||
| void addKeyPressButton (const String& desc, const int index, const bool isReadOnly) | |||||
| { | { | ||||
| deleteAllChildren(); | |||||
| ChangeKeyButton* const b = new ChangeKeyButton (owner, commandID, desc, index); | |||||
| keyChangeButtons.add (b); | |||||
| b->setEnabled (! isReadOnly); | |||||
| b->setVisible (keyChangeButtons.size() <= (int) maxNumAssignments); | |||||
| addChildComponent (b); | |||||
| } | } | ||||
| void paint (Graphics& g) | void paint (Graphics& g) | ||||
| @@ -157,7 +228,7 @@ public: | |||||
| g.setFont (getHeight() * 0.7f); | g.setFont (getHeight() * 0.7f); | ||||
| g.setColour (findColour (KeyMappingEditorComponent::textColourId)); | g.setColour (findColour (KeyMappingEditorComponent::textColourId)); | ||||
| g.drawFittedText (owner.getMappings()->getCommandManager()->getNameOfCommand (commandID), | |||||
| g.drawFittedText (owner.getMappings().getCommandManager()->getNameOfCommand (commandID), | |||||
| 4, 0, jmax (40, getChildComponent (0)->getX() - 5), getHeight(), | 4, 0, jmax (40, getChildComponent (0)->getX() - 5), getHeight(), | ||||
| Justification::centredLeft, true); | Justification::centredLeft, true); | ||||
| } | } | ||||
| @@ -166,33 +237,34 @@ public: | |||||
| { | { | ||||
| int x = getWidth() - 4; | int x = getWidth() - 4; | ||||
| for (int i = getNumChildComponents(); --i >= 0;) | |||||
| for (int i = keyChangeButtons.size(); --i >= 0;) | |||||
| { | { | ||||
| KeyMappingChangeButton* const kb = dynamic_cast <KeyMappingChangeButton*> (getChildComponent (i)); | |||||
| ChangeKeyButton* const b = keyChangeButtons.getUnchecked(i); | |||||
| kb->fitToContent (getHeight() - 2); | |||||
| kb->setTopRightPosition (x, 1); | |||||
| x -= kb->getWidth() + 5; | |||||
| b->fitToContent (getHeight() - 2); | |||||
| b->setTopRightPosition (x, 1); | |||||
| x = b->getX() - 5; | |||||
| } | } | ||||
| } | } | ||||
| enum { maxNumAssignments = 3 }; | |||||
| juce_UseDebuggingNewOperator | juce_UseDebuggingNewOperator | ||||
| private: | private: | ||||
| KeyMappingEditorComponent& owner; | KeyMappingEditorComponent& owner; | ||||
| OwnedArray<ChangeKeyButton> keyChangeButtons; | |||||
| const CommandID commandID; | const CommandID commandID; | ||||
| KeyMappingItemComponent (const KeyMappingItemComponent&); | |||||
| KeyMappingItemComponent& operator= (const KeyMappingItemComponent&); | |||||
| enum { maxNumAssignments = 3 }; | |||||
| ItemComponent (const ItemComponent&); | |||||
| ItemComponent& operator= (const ItemComponent&); | |||||
| }; | }; | ||||
| //============================================================================== | //============================================================================== | ||||
| class KeyMappingTreeViewItem : public TreeViewItem | |||||
| class KeyMappingEditorComponent::MappingItem : public TreeViewItem | |||||
| { | { | ||||
| public: | public: | ||||
| KeyMappingTreeViewItem (KeyMappingEditorComponent& owner_, const CommandID commandID_) | |||||
| MappingItem (KeyMappingEditorComponent& owner_, const CommandID commandID_) | |||||
| : owner (owner_), commandID (commandID_) | : owner (owner_), commandID (commandID_) | ||||
| { | { | ||||
| } | } | ||||
| @@ -203,7 +275,7 @@ public: | |||||
| Component* createItemComponent() | Component* createItemComponent() | ||||
| { | { | ||||
| return new KeyMappingItemComponent (owner, commandID); | |||||
| return new ItemComponent (owner, commandID); | |||||
| } | } | ||||
| juce_UseDebuggingNewOperator | juce_UseDebuggingNewOperator | ||||
| @@ -212,16 +284,16 @@ private: | |||||
| KeyMappingEditorComponent& owner; | KeyMappingEditorComponent& owner; | ||||
| const CommandID commandID; | const CommandID commandID; | ||||
| KeyMappingTreeViewItem (const KeyMappingTreeViewItem&); | |||||
| KeyMappingTreeViewItem& operator= (const KeyMappingTreeViewItem&); | |||||
| MappingItem (const MappingItem&); | |||||
| MappingItem& operator= (const MappingItem&); | |||||
| }; | }; | ||||
| //============================================================================== | //============================================================================== | ||||
| class KeyCategoryTreeViewItem : public TreeViewItem | |||||
| class KeyMappingEditorComponent::CategoryItem : public TreeViewItem | |||||
| { | { | ||||
| public: | public: | ||||
| KeyCategoryTreeViewItem (KeyMappingEditorComponent& owner_, const String& name) | |||||
| CategoryItem (KeyMappingEditorComponent& owner_, const String& name) | |||||
| : owner (owner_), categoryName (name) | : owner (owner_), categoryName (name) | ||||
| { | { | ||||
| } | } | ||||
| @@ -246,12 +318,12 @@ public: | |||||
| { | { | ||||
| if (getNumSubItems() == 0) | if (getNumSubItems() == 0) | ||||
| { | { | ||||
| Array <CommandID> commands (owner.getMappings()->getCommandManager()->getCommandsInCategory (categoryName)); | |||||
| Array <CommandID> commands (owner.getMappings().getCommandManager()->getCommandsInCategory (categoryName)); | |||||
| for (int i = 0; i < commands.size(); ++i) | for (int i = 0; i < commands.size(); ++i) | ||||
| { | { | ||||
| if (owner.shouldCommandBeIncluded (commands[i])) | if (owner.shouldCommandBeIncluded (commands[i])) | ||||
| addSubItem (new KeyMappingTreeViewItem (owner, commands[i])); | |||||
| addSubItem (new MappingItem (owner, commands[i])); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -267,52 +339,99 @@ private: | |||||
| KeyMappingEditorComponent& owner; | KeyMappingEditorComponent& owner; | ||||
| String categoryName; | String categoryName; | ||||
| KeyCategoryTreeViewItem (const KeyCategoryTreeViewItem&); | |||||
| KeyCategoryTreeViewItem& operator= (const KeyCategoryTreeViewItem&); | |||||
| CategoryItem (const CategoryItem&); | |||||
| CategoryItem& operator= (const CategoryItem&); | |||||
| }; | |||||
| //============================================================================== | |||||
| class KeyMappingEditorComponent::TopLevelItem : public TreeViewItem, | |||||
| public ChangeListener, | |||||
| public ButtonListener | |||||
| { | |||||
| public: | |||||
| TopLevelItem (KeyMappingEditorComponent& owner_) | |||||
| : owner (owner_) | |||||
| { | |||||
| setLinesDrawnForSubItems (false); | |||||
| owner.getMappings().addChangeListener (this); | |||||
| } | |||||
| ~TopLevelItem() | |||||
| { | |||||
| owner.getMappings().removeChangeListener (this); | |||||
| } | |||||
| bool mightContainSubItems() { return true; } | |||||
| const String getUniqueName() const { return "keys"; } | |||||
| void changeListenerCallback (void*) | |||||
| { | |||||
| const ScopedPointer <XmlElement> oldOpenness (owner.tree.getOpennessState (true)); | |||||
| clearSubItems(); | |||||
| const StringArray categories (owner.getMappings().getCommandManager()->getCommandCategories()); | |||||
| for (int i = 0; i < categories.size(); ++i) | |||||
| { | |||||
| const Array <CommandID> commands (owner.getMappings().getCommandManager()->getCommandsInCategory (categories[i])); | |||||
| int count = 0; | |||||
| for (int j = 0; j < commands.size(); ++j) | |||||
| if (owner.shouldCommandBeIncluded (commands[j])) | |||||
| ++count; | |||||
| if (count > 0) | |||||
| addSubItem (new CategoryItem (owner, categories[i])); | |||||
| } | |||||
| if (oldOpenness != 0) | |||||
| owner.tree.restoreOpennessState (*oldOpenness); | |||||
| } | |||||
| void buttonClicked (Button*) | |||||
| { | |||||
| if (AlertWindow::showOkCancelBox (AlertWindow::QuestionIcon, | |||||
| TRANS("Reset to defaults"), | |||||
| TRANS("Are you sure you want to reset all the key-mappings to their default state?"), | |||||
| TRANS("Reset"))) | |||||
| { | |||||
| owner.getMappings().resetToDefaultMappings(); | |||||
| } | |||||
| } | |||||
| private: | |||||
| KeyMappingEditorComponent& owner; | |||||
| }; | }; | ||||
| //============================================================================== | //============================================================================== | ||||
| KeyMappingEditorComponent::KeyMappingEditorComponent (KeyPressMappingSet* const mappingManager, | |||||
| KeyMappingEditorComponent::KeyMappingEditorComponent (KeyPressMappingSet& mappingManager, | |||||
| const bool showResetToDefaultButton) | const bool showResetToDefaultButton) | ||||
| : mappings (mappingManager), | : mappings (mappingManager), | ||||
| resetButton (TRANS ("reset to defaults")) | resetButton (TRANS ("reset to defaults")) | ||||
| { | { | ||||
| jassert (mappingManager != 0); // can't be null! | |||||
| mappingManager->addChangeListener (this); | |||||
| setLinesDrawnForSubItems (false); | |||||
| treeItem = new TopLevelItem (*this); | |||||
| if (showResetToDefaultButton) | if (showResetToDefaultButton) | ||||
| { | { | ||||
| addAndMakeVisible (&resetButton); | addAndMakeVisible (&resetButton); | ||||
| resetButton.addButtonListener (this); | |||||
| resetButton.addButtonListener (treeItem); | |||||
| } | } | ||||
| addAndMakeVisible (&tree); | addAndMakeVisible (&tree); | ||||
| tree.setColour (TreeView::backgroundColourId, findColour (backgroundColourId)); | tree.setColour (TreeView::backgroundColourId, findColour (backgroundColourId)); | ||||
| tree.setRootItemVisible (false); | tree.setRootItemVisible (false); | ||||
| tree.setDefaultOpenness (true); | tree.setDefaultOpenness (true); | ||||
| tree.setRootItem (this); | |||||
| tree.setRootItem (treeItem); | |||||
| } | } | ||||
| KeyMappingEditorComponent::~KeyMappingEditorComponent() | KeyMappingEditorComponent::~KeyMappingEditorComponent() | ||||
| { | { | ||||
| mappings->removeChangeListener (this); | |||||
| tree.setRootItem (0); | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| bool KeyMappingEditorComponent::mightContainSubItems() | |||||
| { | |||||
| return true; | |||||
| } | |||||
| const String KeyMappingEditorComponent::getUniqueName() const | |||||
| { | |||||
| return "keys"; | |||||
| } | |||||
| void KeyMappingEditorComponent::setColours (const Colour& mainBackground, | void KeyMappingEditorComponent::setColours (const Colour& mainBackground, | ||||
| const Colour& textColour) | const Colour& textColour) | ||||
| { | { | ||||
| @@ -323,7 +442,7 @@ void KeyMappingEditorComponent::setColours (const Colour& mainBackground, | |||||
| void KeyMappingEditorComponent::parentHierarchyChanged() | void KeyMappingEditorComponent::parentHierarchyChanged() | ||||
| { | { | ||||
| changeListenerCallback (0); | |||||
| treeItem->changeListenerCallback (0); | |||||
| } | } | ||||
| void KeyMappingEditorComponent::resized() | void KeyMappingEditorComponent::resized() | ||||
| @@ -343,157 +462,19 @@ void KeyMappingEditorComponent::resized() | |||||
| tree.setBounds (0, 0, getWidth(), h); | tree.setBounds (0, 0, getWidth(), h); | ||||
| } | } | ||||
| void KeyMappingEditorComponent::buttonClicked (Button* button) | |||||
| { | |||||
| if (button == &resetButton) | |||||
| { | |||||
| if (AlertWindow::showOkCancelBox (AlertWindow::QuestionIcon, | |||||
| TRANS("Reset to defaults"), | |||||
| TRANS("Are you sure you want to reset all the key-mappings to their default state?"), | |||||
| TRANS("Reset"))) | |||||
| { | |||||
| mappings->resetToDefaultMappings(); | |||||
| } | |||||
| } | |||||
| } | |||||
| void KeyMappingEditorComponent::changeListenerCallback (void*) | |||||
| { | |||||
| ScopedPointer <XmlElement> oldOpenness (tree.getOpennessState (true)); | |||||
| clearSubItems(); | |||||
| const StringArray categories (mappings->getCommandManager()->getCommandCategories()); | |||||
| for (int i = 0; i < categories.size(); ++i) | |||||
| { | |||||
| const Array <CommandID> commands (mappings->getCommandManager()->getCommandsInCategory (categories[i])); | |||||
| int count = 0; | |||||
| for (int j = 0; j < commands.size(); ++j) | |||||
| if (shouldCommandBeIncluded (commands[j])) | |||||
| ++count; | |||||
| if (count > 0) | |||||
| addSubItem (new KeyCategoryTreeViewItem (*this, categories[i])); | |||||
| } | |||||
| if (oldOpenness != 0) | |||||
| tree.restoreOpennessState (*oldOpenness); | |||||
| } | |||||
| //============================================================================== | |||||
| class KeyEntryWindow : public AlertWindow | |||||
| { | |||||
| public: | |||||
| KeyEntryWindow (KeyMappingEditorComponent& owner_) | |||||
| : AlertWindow (TRANS("New key-mapping"), | |||||
| TRANS("Please press a key combination now..."), | |||||
| AlertWindow::NoIcon), | |||||
| owner (owner_) | |||||
| { | |||||
| addButton (TRANS("ok"), 1); | |||||
| addButton (TRANS("cancel"), 0); | |||||
| // (avoid return + escape keys getting processed by the buttons..) | |||||
| for (int i = getNumChildComponents(); --i >= 0;) | |||||
| getChildComponent (i)->setWantsKeyboardFocus (false); | |||||
| setWantsKeyboardFocus (true); | |||||
| grabKeyboardFocus(); | |||||
| } | |||||
| ~KeyEntryWindow() | |||||
| { | |||||
| } | |||||
| bool keyPressed (const KeyPress& key) | |||||
| { | |||||
| lastPress = key; | |||||
| String message (TRANS("Key: ") + owner.getDescriptionForKeyPress (key)); | |||||
| const CommandID previousCommand = owner.getMappings()->findCommandForKeyPress (key); | |||||
| if (previousCommand != 0) | |||||
| { | |||||
| message << "\n\n" | |||||
| << TRANS("(Currently assigned to \"") | |||||
| << owner.getMappings()->getCommandManager()->getNameOfCommand (previousCommand) | |||||
| << "\")"; | |||||
| } | |||||
| setMessage (message); | |||||
| return true; | |||||
| } | |||||
| bool keyStateChanged (bool) | |||||
| { | |||||
| return true; | |||||
| } | |||||
| KeyPress lastPress; | |||||
| juce_UseDebuggingNewOperator | |||||
| private: | |||||
| KeyMappingEditorComponent& owner; | |||||
| KeyEntryWindow (const KeyEntryWindow&); | |||||
| KeyEntryWindow& operator= (const KeyEntryWindow&); | |||||
| }; | |||||
| void KeyMappingEditorComponent::assignNewKey (const CommandID commandID, const int index) | |||||
| { | |||||
| KeyEntryWindow entryWindow (*this); | |||||
| if (entryWindow.runModalLoop() != 0) | |||||
| { | |||||
| entryWindow.setVisible (false); | |||||
| if (entryWindow.lastPress.isValid()) | |||||
| { | |||||
| const CommandID previousCommand = mappings->findCommandForKeyPress (entryWindow.lastPress); | |||||
| if (previousCommand != 0) | |||||
| { | |||||
| if (! AlertWindow::showOkCancelBox (AlertWindow::WarningIcon, | |||||
| TRANS("Change key-mapping"), | |||||
| TRANS("This key is already assigned to the command \"") | |||||
| + mappings->getCommandManager()->getNameOfCommand (previousCommand) | |||||
| + TRANS("\"\n\nDo you want to re-assign it to this new command instead?"), | |||||
| TRANS("re-assign"), | |||||
| TRANS("cancel"))) | |||||
| { | |||||
| return; | |||||
| } | |||||
| } | |||||
| mappings->removeKeyPress (entryWindow.lastPress); | |||||
| if (index >= 0) | |||||
| mappings->removeKeyPress (commandID, index); | |||||
| mappings->addKeyPress (commandID, entryWindow.lastPress, index); | |||||
| } | |||||
| } | |||||
| } | |||||
| //============================================================================== | //============================================================================== | ||||
| bool KeyMappingEditorComponent::shouldCommandBeIncluded (const CommandID commandID) | bool KeyMappingEditorComponent::shouldCommandBeIncluded (const CommandID commandID) | ||||
| { | { | ||||
| const ApplicationCommandInfo* const ci = mappings->getCommandManager()->getCommandForID (commandID); | |||||
| const ApplicationCommandInfo* const ci = mappings.getCommandManager()->getCommandForID (commandID); | |||||
| return (ci != 0) && ((ci->flags & ApplicationCommandInfo::hiddenFromKeyEditor) == 0); | |||||
| return ci != 0 && (ci->flags & ApplicationCommandInfo::hiddenFromKeyEditor) == 0; | |||||
| } | } | ||||
| bool KeyMappingEditorComponent::isCommandReadOnly (const CommandID commandID) | bool KeyMappingEditorComponent::isCommandReadOnly (const CommandID commandID) | ||||
| { | { | ||||
| const ApplicationCommandInfo* const ci = mappings->getCommandManager()->getCommandForID (commandID); | |||||
| const ApplicationCommandInfo* const ci = mappings.getCommandManager()->getCommandForID (commandID); | |||||
| return (ci != 0) && ((ci->flags & ApplicationCommandInfo::readOnlyInKeyEditor) != 0); | |||||
| return ci != 0 && (ci->flags & ApplicationCommandInfo::readOnlyInKeyEditor) != 0; | |||||
| } | } | ||||
| const String KeyMappingEditorComponent::getDescriptionForKeyPress (const KeyPress& key) | const String KeyMappingEditorComponent::getDescriptionForKeyPress (const KeyPress& key) | ||||
| @@ -38,23 +38,18 @@ | |||||
| @see KeyPressMappingSet | @see KeyPressMappingSet | ||||
| */ | */ | ||||
| class JUCE_API KeyMappingEditorComponent : public Component, | |||||
| public TreeViewItem, | |||||
| public ChangeListener, | |||||
| private ButtonListener // (can't use Button::Listener due to idiotic VC2005 bug) | |||||
| class JUCE_API KeyMappingEditorComponent : public Component | |||||
| { | { | ||||
| public: | public: | ||||
| //============================================================================== | //============================================================================== | ||||
| /** Creates a KeyMappingEditorComponent. | /** Creates a KeyMappingEditorComponent. | ||||
| @param mappingSet this is the set of mappings to display and | |||||
| edit. Make sure the mappings object is not | |||||
| deleted before this component! | |||||
| @param showResetToDefaultButton if true, then at the bottom of the | |||||
| list, the component will include a 'reset to | |||||
| defaults' button. | |||||
| @param mappingSet this is the set of mappings to display and edit. Make sure the | |||||
| mappings object is not deleted before this component! | |||||
| @param showResetToDefaultButton if true, then at the bottom of the list, the | |||||
| component will include a 'reset to defaults' button. | |||||
| */ | */ | ||||
| KeyMappingEditorComponent (KeyPressMappingSet* mappingSet, | |||||
| KeyMappingEditorComponent (KeyPressMappingSet& mappingSet, | |||||
| bool showResetToDefaultButton); | bool showResetToDefaultButton); | ||||
| /** Destructor. */ | /** Destructor. */ | ||||
| @@ -69,9 +64,8 @@ public: | |||||
| void setColours (const Colour& mainBackground, | void setColours (const Colour& mainBackground, | ||||
| const Colour& textColour); | const Colour& textColour); | ||||
| /** Returns the KeyPressMappingSet that this component is acting upon. | |||||
| */ | |||||
| KeyPressMappingSet* getMappings() const throw() { return mappings; } | |||||
| /** Returns the KeyPressMappingSet that this component is acting upon. */ | |||||
| KeyPressMappingSet& getMappings() const throw() { return mappings; } | |||||
| //============================================================================== | //============================================================================== | ||||
| @@ -120,29 +114,24 @@ public: | |||||
| void parentHierarchyChanged(); | void parentHierarchyChanged(); | ||||
| /** @internal */ | /** @internal */ | ||||
| void resized(); | void resized(); | ||||
| /** @internal */ | |||||
| void changeListenerCallback (void*); | |||||
| /** @internal */ | |||||
| bool mightContainSubItems(); | |||||
| /** @internal */ | |||||
| const String getUniqueName() const; | |||||
| /** @internal */ | |||||
| void buttonClicked (Button* button); | |||||
| juce_UseDebuggingNewOperator | juce_UseDebuggingNewOperator | ||||
| private: | private: | ||||
| //============================================================================== | //============================================================================== | ||||
| friend class KeyMappingTreeViewItem; | |||||
| friend class KeyCategoryTreeViewItem; | |||||
| friend class KeyMappingItemComponent; | |||||
| friend class KeyMappingChangeButton; | |||||
| KeyPressMappingSet* mappings; | |||||
| KeyPressMappingSet& mappings; | |||||
| TreeView tree; | TreeView tree; | ||||
| TextButton resetButton; | TextButton resetButton; | ||||
| void assignNewKey (CommandID commandID, int index); | |||||
| class TopLevelItem; | |||||
| class ChangeKeyButton; | |||||
| class MappingItem; | |||||
| class CategoryItem; | |||||
| class ItemComponent; | |||||
| friend class TopLevelItem; | |||||
| friend class OwnedArray <ChangeKeyButton>; | |||||
| friend class ScopedPointer<TopLevelItem>; | |||||
| ScopedPointer<TopLevelItem> treeItem; | |||||
| KeyMappingEditorComponent (const KeyMappingEditorComponent&); | KeyMappingEditorComponent (const KeyMappingEditorComponent&); | ||||
| KeyMappingEditorComponent& operator= (const KeyMappingEditorComponent&); | KeyMappingEditorComponent& operator= (const KeyMappingEditorComponent&); | ||||
| @@ -58,7 +58,7 @@ Viewport::Viewport (const String& componentName) | |||||
| Viewport::~Viewport() | Viewport::~Viewport() | ||||
| { | { | ||||
| contentHolder.deleteAllChildren(); | |||||
| deleteContentComp(); | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -67,15 +67,19 @@ void Viewport::visibleAreaChanged (int, int, int, int) | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| void Viewport::deleteContentComp() | |||||
| { | |||||
| // This sets the content comp to a null pointer before deleting the old one, in case | |||||
| // anything tries to use the old one while it's in mid-deletion.. | |||||
| ScopedPointer<Component> oldCompDeleter (contentComp); | |||||
| contentComp = 0; | |||||
| } | |||||
| void Viewport::setViewedComponent (Component* const newViewedComponent) | void Viewport::setViewedComponent (Component* const newViewedComponent) | ||||
| { | { | ||||
| if (contentComp.getComponent() != newViewedComponent) | if (contentComp.getComponent() != newViewedComponent) | ||||
| { | { | ||||
| { | |||||
| ScopedPointer<Component> oldCompDeleter (contentComp); | |||||
| contentComp = 0; | |||||
| } | |||||
| deleteContentComp(); | |||||
| contentComp = newViewedComponent; | contentComp = newViewedComponent; | ||||
| if (contentComp != 0) | if (contentComp != 0) | ||||
| @@ -89,15 +93,8 @@ void Viewport::setViewedComponent (Component* const newViewedComponent) | |||||
| } | } | ||||
| } | } | ||||
| int Viewport::getMaximumVisibleWidth() const | |||||
| { | |||||
| return contentHolder.getWidth(); | |||||
| } | |||||
| int Viewport::getMaximumVisibleHeight() const | |||||
| { | |||||
| return contentHolder.getHeight(); | |||||
| } | |||||
| int Viewport::getMaximumVisibleWidth() const { return contentHolder.getWidth(); } | |||||
| int Viewport::getMaximumVisibleHeight() const { return contentHolder.getHeight(); } | |||||
| void Viewport::setViewPosition (const int xPixelsOffset, const int yPixelsOffset) | void Viewport::setViewPosition (const int xPixelsOffset, const int yPixelsOffset) | ||||
| { | { | ||||
| @@ -264,6 +264,7 @@ private: | |||||
| ScrollBar horizontalScrollBar; | ScrollBar horizontalScrollBar; | ||||
| void updateVisibleArea(); | void updateVisibleArea(); | ||||
| void deleteContentComp(); | |||||
| Viewport (const Viewport&); | Viewport (const Viewport&); | ||||
| Viewport& operator= (const Viewport&); | Viewport& operator= (const Viewport&); | ||||
| @@ -148,12 +148,17 @@ class PopupMenu::ItemComponent : public Component | |||||
| { | { | ||||
| public: | public: | ||||
| //============================================================================== | //============================================================================== | ||||
| ItemComponent (const PopupMenu::Item& itemInfo_) | |||||
| ItemComponent (const PopupMenu::Item& itemInfo_, int standardItemHeight) | |||||
| : itemInfo (itemInfo_), | : itemInfo (itemInfo_), | ||||
| isHighlighted (false) | isHighlighted (false) | ||||
| { | { | ||||
| if (itemInfo.customComp != 0) | if (itemInfo.customComp != 0) | ||||
| addAndMakeVisible (itemInfo.customComp); | addAndMakeVisible (itemInfo.customComp); | ||||
| int itemW = 80; | |||||
| int itemH = 16; | |||||
| getIdealSize (itemW, itemH, standardItemHeight); | |||||
| setSize (itemW, jlimit (2, 600, itemH)); | |||||
| } | } | ||||
| ~ItemComponent() | ~ItemComponent() | ||||
| @@ -258,35 +263,68 @@ class PopupMenu::Window : public Component, | |||||
| { | { | ||||
| public: | public: | ||||
| //============================================================================== | //============================================================================== | ||||
| Window() | |||||
| Window (const PopupMenu& menu, Window* const owner_, const Rectangle<int>& target, | |||||
| const bool alignToRectangle, const int itemIdThatMustBeVisible, | |||||
| const int minimumWidth_, const int maximumNumColumns_, | |||||
| const int standardItemHeight_, const bool dismissOnMouseUp_, | |||||
| ApplicationCommandManager** const managerOfChosenCommand_, | |||||
| Component* const componentAttachedTo_) | |||||
| : Component ("menu"), | : Component ("menu"), | ||||
| owner (0), | |||||
| owner (owner_), | |||||
| activeSubMenu (0), | activeSubMenu (0), | ||||
| managerOfChosenCommand (0), | |||||
| minimumWidth (0), | |||||
| maximumNumColumns (7), | |||||
| standardItemHeight (0), | |||||
| managerOfChosenCommand (managerOfChosenCommand_), | |||||
| componentAttachedTo (componentAttachedTo_), | |||||
| componentAttachedToOriginal (componentAttachedTo_), | |||||
| minimumWidth (minimumWidth_), | |||||
| maximumNumColumns (maximumNumColumns_), | |||||
| standardItemHeight (standardItemHeight_), | |||||
| isOver (false), | isOver (false), | ||||
| hasBeenOver (false), | hasBeenOver (false), | ||||
| isDown (false), | isDown (false), | ||||
| needsToScroll (false), | needsToScroll (false), | ||||
| dismissOnMouseUp (dismissOnMouseUp_), | |||||
| hideOnExit (false), | hideOnExit (false), | ||||
| disableMouseMoves (false), | disableMouseMoves (false), | ||||
| hasAnyJuceCompHadFocus (false), | hasAnyJuceCompHadFocus (false), | ||||
| numColumns (0), | numColumns (0), | ||||
| contentHeight (0), | contentHeight (0), | ||||
| childYOffset (0), | childYOffset (0), | ||||
| menuCreationTime (Time::getMillisecondCounter()), | |||||
| timeEnteredCurrentChildComp (0), | timeEnteredCurrentChildComp (0), | ||||
| scrollAcceleration (1.0) | scrollAcceleration (1.0) | ||||
| { | { | ||||
| menuCreationTime = lastFocused = lastScroll = Time::getMillisecondCounter(); | |||||
| setWantsKeyboardFocus (true); | |||||
| lastFocused = lastScroll = menuCreationTime; | |||||
| setWantsKeyboardFocus (false); | |||||
| setMouseClickGrabsKeyboardFocus (false); | setMouseClickGrabsKeyboardFocus (false); | ||||
| setAlwaysOnTop (true); | setAlwaysOnTop (true); | ||||
| Desktop::getInstance().addGlobalMouseListener (this); | |||||
| setLookAndFeel (menu.lookAndFeel); | |||||
| setOpaque (getLookAndFeel().findColour (PopupMenu::backgroundColourId).isOpaque() || ! Desktop::canUseSemiTransparentWindows()); | |||||
| for (int i = 0; i < menu.items.size(); ++i) | |||||
| { | |||||
| PopupMenu::ItemComponent* const itemComp = new PopupMenu::ItemComponent (*menu.items.getUnchecked(i), standardItemHeight); | |||||
| items.add (itemComp); | |||||
| addAndMakeVisible (itemComp); | |||||
| itemComp->addMouseListener (this, false); | |||||
| } | |||||
| calculateWindowPos (target, alignToRectangle); | |||||
| setTopLeftPosition (windowPos.getX(), windowPos.getY()); | |||||
| updateYPositions(); | |||||
| if (itemIdThatMustBeVisible != 0) | |||||
| { | |||||
| const int y = target.getY() - windowPos.getY(); | |||||
| ensureItemIsVisible (itemIdThatMustBeVisible, | |||||
| (((unsigned int) y) < (unsigned int) windowPos.getHeight()) ? y : -1); | |||||
| } | |||||
| resizeToBestWindowPos(); | |||||
| addToDesktop (ComponentPeer::windowIsTemporary | getLookAndFeel().getMenuWindowFlags()); | |||||
| getActiveWindows().add (this); | getActiveWindows().add (this); | ||||
| Desktop::getInstance().addGlobalMouseListener (this); | |||||
| } | } | ||||
| ~Window() | ~Window() | ||||
| @@ -294,69 +332,26 @@ public: | |||||
| getActiveWindows().removeValue (this); | getActiveWindows().removeValue (this); | ||||
| Desktop::getInstance().removeGlobalMouseListener (this); | Desktop::getInstance().removeGlobalMouseListener (this); | ||||
| activeSubMenu = 0; | activeSubMenu = 0; | ||||
| deleteAllChildren(); | |||||
| items.clear(); | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| static Window* create (const PopupMenu& menu, | static Window* create (const PopupMenu& menu, | ||||
| const bool dismissOnMouseUp, | |||||
| bool dismissOnMouseUp, | |||||
| Window* const owner_, | Window* const owner_, | ||||
| const Rectangle<int>& target, | const Rectangle<int>& target, | ||||
| const int minimumWidth, | |||||
| const int maximumNumColumns, | |||||
| const int standardItemHeight, | |||||
| const bool alignToRectangle, | |||||
| const int itemIdThatMustBeVisible, | |||||
| int minimumWidth, | |||||
| int maximumNumColumns, | |||||
| int standardItemHeight, | |||||
| bool alignToRectangle, | |||||
| int itemIdThatMustBeVisible, | |||||
| ApplicationCommandManager** managerOfChosenCommand, | ApplicationCommandManager** managerOfChosenCommand, | ||||
| Component* const componentAttachedTo) | |||||
| Component* componentAttachedTo) | |||||
| { | { | ||||
| if (menu.items.size() > 0) | if (menu.items.size() > 0) | ||||
| { | |||||
| int totalItems = 0; | |||||
| ScopedPointer <Window> mw (new Window()); | |||||
| mw->setLookAndFeel (menu.lookAndFeel); | |||||
| mw->setWantsKeyboardFocus (false); | |||||
| mw->setOpaque (mw->getLookAndFeel().findColour (PopupMenu::backgroundColourId).isOpaque() || ! Desktop::canUseSemiTransparentWindows()); | |||||
| mw->minimumWidth = minimumWidth; | |||||
| mw->maximumNumColumns = maximumNumColumns; | |||||
| mw->standardItemHeight = standardItemHeight; | |||||
| mw->dismissOnMouseUp = dismissOnMouseUp; | |||||
| for (int i = 0; i < menu.items.size(); ++i) | |||||
| { | |||||
| PopupMenu::Item* const item = menu.items.getUnchecked(i); | |||||
| mw->addItem (*item); | |||||
| ++totalItems; | |||||
| } | |||||
| if (totalItems > 0) | |||||
| { | |||||
| mw->owner = owner_; | |||||
| mw->managerOfChosenCommand = managerOfChosenCommand; | |||||
| mw->componentAttachedTo = componentAttachedTo; | |||||
| mw->componentAttachedToOriginal = componentAttachedTo; | |||||
| mw->calculateWindowPos (target, alignToRectangle); | |||||
| mw->setTopLeftPosition (mw->windowPos.getX(), | |||||
| mw->windowPos.getY()); | |||||
| mw->updateYPositions(); | |||||
| if (itemIdThatMustBeVisible != 0) | |||||
| { | |||||
| const int y = target.getY() - mw->windowPos.getY(); | |||||
| mw->ensureItemIsVisible (itemIdThatMustBeVisible, | |||||
| (((unsigned int) y) < (unsigned int) mw->windowPos.getHeight()) ? y : -1); | |||||
| } | |||||
| mw->resizeToBestWindowPos(); | |||||
| mw->addToDesktop (ComponentPeer::windowIsTemporary | |||||
| | mw->getLookAndFeel().getMenuWindowFlags()); | |||||
| return mw.release(); | |||||
| } | |||||
| } | |||||
| return new Window (menu, owner_, target, alignToRectangle, itemIdThatMustBeVisible, | |||||
| minimumWidth, maximumNumColumns, standardItemHeight, dismissOnMouseUp, | |||||
| managerOfChosenCommand, componentAttachedTo); | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| @@ -394,19 +389,6 @@ public: | |||||
| : childYOffset > 0); | : childYOffset > 0); | ||||
| } | } | ||||
| //============================================================================== | |||||
| void addItem (const PopupMenu::Item& item) | |||||
| { | |||||
| PopupMenu::ItemComponent* const mic = new PopupMenu::ItemComponent (item); | |||||
| addAndMakeVisible (mic); | |||||
| int itemW = 80; | |||||
| int itemH = 16; | |||||
| mic->getIdealSize (itemW, itemH, standardItemHeight); | |||||
| mic->setSize (itemW, jlimit (2, 600, itemH)); | |||||
| mic->addMouseListener (this, false); | |||||
| } | |||||
| //============================================================================== | //============================================================================== | ||||
| // hide this and all sub-comps | // hide this and all sub-comps | ||||
| void hide (const PopupMenu::Item* const item, const bool makeInvisible) | void hide (const PopupMenu::Item* const item, const bool makeInvisible) | ||||
| @@ -610,8 +592,8 @@ public: | |||||
| scrollAcceleration = jmin (4.0, scrollAcceleration * 1.04); | scrollAcceleration = jmin (4.0, scrollAcceleration * 1.04); | ||||
| int amount = 0; | int amount = 0; | ||||
| for (int i = 0; i < getNumChildComponents() && amount == 0; ++i) | |||||
| amount = ((int) scrollAcceleration) * getChildComponent (i)->getHeight(); | |||||
| for (int i = 0; i < items.size() && amount == 0; ++i) | |||||
| amount = ((int) scrollAcceleration) * items.getUnchecked(i)->getHeight(); | |||||
| alterChildYPos (localMousePos.getY() < PopupMenuSettings::scrollZone ? -amount : amount); | alterChildYPos (localMousePos.getY() < PopupMenuSettings::scrollZone ? -amount : amount); | ||||
| @@ -714,6 +696,7 @@ public: | |||||
| private: | private: | ||||
| Window* owner; | Window* owner; | ||||
| OwnedArray <PopupMenu::ItemComponent> items; | |||||
| Component::SafePointer<PopupMenu::ItemComponent> currentChild; | Component::SafePointer<PopupMenu::ItemComponent> currentChild; | ||||
| ScopedPointer <Window> activeSubMenu; | ScopedPointer <Window> activeSubMenu; | ||||
| ApplicationCommandManager** managerOfChosenCommand; | ApplicationCommandManager** managerOfChosenCommand; | ||||
| @@ -899,13 +882,13 @@ private: | |||||
| { | { | ||||
| int i, colW = 50, colH = 0; | int i, colW = 50, colH = 0; | ||||
| const int numChildren = jmin (getNumChildComponents() - childNum, | |||||
| (getNumChildComponents() + numColumns - 1) / numColumns); | |||||
| const int numChildren = jmin (items.size() - childNum, | |||||
| (items.size() + numColumns - 1) / numColumns); | |||||
| for (i = numChildren; --i >= 0;) | for (i = numChildren; --i >= 0;) | ||||
| { | { | ||||
| colW = jmax (colW, getChildComponent (childNum + i)->getWidth()); | |||||
| colH += getChildComponent (childNum + i)->getHeight(); | |||||
| colW = jmax (colW, items.getUnchecked (childNum + i)->getWidth()); | |||||
| colH += items.getUnchecked (childNum + i)->getHeight(); | |||||
| } | } | ||||
| colW = jmin (maxMenuW / jmax (1, numColumns - 2), colW + PopupMenuSettings::borderSize * 2); | colW = jmin (maxMenuW / jmax (1, numColumns - 2), colW + PopupMenuSettings::borderSize * 2); | ||||
| @@ -932,9 +915,9 @@ private: | |||||
| { | { | ||||
| jassert (itemId != 0) | jassert (itemId != 0) | ||||
| for (int i = getNumChildComponents(); --i >= 0;) | |||||
| for (int i = items.size(); --i >= 0;) | |||||
| { | { | ||||
| PopupMenu::ItemComponent* const m = static_cast <PopupMenu::ItemComponent*> (getChildComponent (i)); | |||||
| PopupMenu::ItemComponent* const m = items.getUnchecked(i); | |||||
| if (m != 0 | if (m != 0 | ||||
| && m->itemInfo.itemId == itemId | && m->itemInfo.itemId == itemId | ||||
| @@ -1029,8 +1012,8 @@ private: | |||||
| for (int col = 0; col < numColumns; ++col) | for (int col = 0; col < numColumns; ++col) | ||||
| { | { | ||||
| const int numChildren = jmin (getNumChildComponents() - childNum, | |||||
| (getNumChildComponents() + numColumns - 1) / numColumns); | |||||
| const int numChildren = jmin (items.size() - childNum, | |||||
| (items.size() + numColumns - 1) / numColumns); | |||||
| const int colW = columnWidths [col]; | const int colW = columnWidths [col]; | ||||
| @@ -1038,7 +1021,7 @@ private: | |||||
| for (int i = 0; i < numChildren; ++i) | for (int i = 0; i < numChildren; ++i) | ||||
| { | { | ||||
| Component* const c = getChildComponent (childNum + i); | |||||
| Component* const c = items.getUnchecked (childNum + i); | |||||
| c->setBounds (x, y, colW, c->getHeight()); | c->setBounds (x, y, colW, c->getHeight()); | ||||
| y += c->getHeight(); | y += c->getHeight(); | ||||
| } | } | ||||
| @@ -1187,14 +1170,14 @@ private: | |||||
| disableTimerUntilMouseMoves(); | disableTimerUntilMouseMoves(); | ||||
| PopupMenu::ItemComponent* mic = 0; | PopupMenu::ItemComponent* mic = 0; | ||||
| bool wasLastOne = (currentChild == 0); | bool wasLastOne = (currentChild == 0); | ||||
| const int numItems = getNumChildComponents(); | |||||
| const int numItems = items.size(); | |||||
| for (int i = 0; i < numItems + 1; ++i) | for (int i = 0; i < numItems + 1; ++i) | ||||
| { | { | ||||
| int index = (delta > 0) ? i : (numItems - 1 - i); | int index = (delta > 0) ? i : (numItems - 1 - i); | ||||
| index = (index + numItems) % numItems; | index = (index + numItems) % numItems; | ||||
| mic = dynamic_cast <PopupMenu::ItemComponent*> (getChildComponent (index)); | |||||
| mic = items.getUnchecked (index); | |||||
| if (mic != 0 && (mic->itemInfo.canBeTriggered() || mic->itemInfo.hasActiveSubMenu()) | if (mic != 0 && (mic->itemInfo.canBeTriggered() || mic->itemInfo.hasActiveSubMenu()) | ||||
| && wasLastOne) | && wasLastOne) | ||||
| @@ -1713,7 +1696,7 @@ bool PopupMenu::MenuItemIterator::next() | |||||
| isSeparator = item->isSeparator; | isSeparator = item->isSeparator; | ||||
| isTicked = item->isTicked; | isTicked = item->isTicked; | ||||
| isEnabled = item->active; | isEnabled = item->active; | ||||
| isSectionHeader = dynamic_cast <HeaderItemComponent*> ((PopupMenuCustomComponent*) item->customComp) != 0; | |||||
| isSectionHeader = dynamic_cast <HeaderItemComponent*> (static_cast <PopupMenuCustomComponent*> (item->customComp)) != 0; | |||||
| isCustomComponent = (! isSectionHeader) && item->customComp != 0; | isCustomComponent = (! isSectionHeader) && item->customComp != 0; | ||||
| customColour = item->usesColour ? &(item->textColour) : 0; | customColour = item->usesColour ? &(item->textColour) : 0; | ||||
| customImage = item->image; | customImage = item->image; | ||||
| @@ -394,6 +394,7 @@ private: | |||||
| friend class PopupMenuCustomComponent; | friend class PopupMenuCustomComponent; | ||||
| friend class MenuBarComponent; | friend class MenuBarComponent; | ||||
| friend class OwnedArray <Item>; | friend class OwnedArray <Item>; | ||||
| friend class OwnedArray <ItemComponent>; | |||||
| friend class ScopedPointer <Window>; | friend class ScopedPointer <Window>; | ||||
| OwnedArray <Item> items; | OwnedArray <Item> items; | ||||
| @@ -85,7 +85,7 @@ public: | |||||
| const Point<int> relativePos (comp->getLocalPoint (0, screenPos)); | const Point<int> relativePos (comp->getLocalPoint (0, screenPos)); | ||||
| // (the contains() call is needed to test for overlapping desktop windows) | // (the contains() call is needed to test for overlapping desktop windows) | ||||
| if (comp->contains (relativePos.getX(), relativePos.getY())) | |||||
| if (comp->contains (relativePos)) | |||||
| return comp->getComponentAt (relativePos); | return comp->getComponentAt (relativePos); | ||||
| } | } | ||||
| @@ -32,52 +32,29 @@ BEGIN_JUCE_NAMESPACE | |||||
| #include "../../../text/juce_LocalisedStrings.h" | #include "../../../text/juce_LocalisedStrings.h" | ||||
| //============================================================================== | |||||
| class PropertyPanel::PropertyHolderComponent : public Component | |||||
| { | |||||
| public: | |||||
| PropertyHolderComponent() | |||||
| { | |||||
| } | |||||
| ~PropertyHolderComponent() | |||||
| { | |||||
| deleteAllChildren(); | |||||
| } | |||||
| void paint (Graphics&) | |||||
| { | |||||
| } | |||||
| void updateLayout (int width); | |||||
| void refreshAll() const; | |||||
| private: | |||||
| PropertyHolderComponent (const PropertyHolderComponent&); | |||||
| PropertyHolderComponent& operator= (const PropertyHolderComponent&); | |||||
| }; | |||||
| //============================================================================== | //============================================================================== | ||||
| class PropertySectionComponent : public Component | class PropertySectionComponent : public Component | ||||
| { | { | ||||
| public: | public: | ||||
| PropertySectionComponent (const String& sectionTitle, | PropertySectionComponent (const String& sectionTitle, | ||||
| const Array <PropertyComponent*>& newProperties, | const Array <PropertyComponent*>& newProperties, | ||||
| const bool open) | |||||
| const bool sectionIsOpen_) | |||||
| : Component (sectionTitle), | : Component (sectionTitle), | ||||
| titleHeight (sectionTitle.isNotEmpty() ? 22 : 0), | titleHeight (sectionTitle.isNotEmpty() ? 22 : 0), | ||||
| isOpen_ (open) | |||||
| sectionIsOpen (sectionIsOpen_) | |||||
| { | { | ||||
| for (int i = newProperties.size(); --i >= 0;) | |||||
| propertyComps.addArray (newProperties); | |||||
| for (int i = propertyComps.size(); --i >= 0;) | |||||
| { | { | ||||
| addAndMakeVisible (newProperties.getUnchecked(i)); | |||||
| newProperties.getUnchecked(i)->refresh(); | |||||
| addAndMakeVisible (propertyComps.getUnchecked(i)); | |||||
| propertyComps.getUnchecked(i)->refresh(); | |||||
| } | } | ||||
| } | } | ||||
| ~PropertySectionComponent() | ~PropertySectionComponent() | ||||
| { | { | ||||
| deleteAllChildren(); | |||||
| propertyComps.clear(); | |||||
| } | } | ||||
| void paint (Graphics& g) | void paint (Graphics& g) | ||||
| @@ -90,16 +67,11 @@ public: | |||||
| { | { | ||||
| int y = titleHeight; | int y = titleHeight; | ||||
| for (int i = getNumChildComponents(); --i >= 0;) | |||||
| for (int i = 0; i < propertyComps.size(); ++i) | |||||
| { | { | ||||
| PropertyComponent* const pec = dynamic_cast <PropertyComponent*> (getChildComponent (i)); | |||||
| if (pec != 0) | |||||
| { | |||||
| const int prefH = pec->getPreferredHeight(); | |||||
| pec->setBounds (1, y, getWidth() - 2, prefH); | |||||
| y += prefH; | |||||
| } | |||||
| PropertyComponent* const pec = propertyComps.getUnchecked (i); | |||||
| pec->setBounds (1, y, getWidth() - 2, pec->getPreferredHeight()); | |||||
| y = pec->getBottom(); | |||||
| } | } | ||||
| } | } | ||||
| @@ -109,13 +81,8 @@ public: | |||||
| if (isOpen()) | if (isOpen()) | ||||
| { | { | ||||
| for (int i = 0; i < getNumChildComponents(); ++i) | |||||
| { | |||||
| PropertyComponent* pec = dynamic_cast <PropertyComponent*> (getChildComponent (i)); | |||||
| if (pec != 0) | |||||
| y += pec->getPreferredHeight(); | |||||
| } | |||||
| for (int i = propertyComps.size(); --i >= 0;) | |||||
| y += propertyComps.getUnchecked(i)->getPreferredHeight(); | |||||
| } | } | ||||
| return y; | return y; | ||||
| @@ -123,19 +90,13 @@ public: | |||||
| void setOpen (const bool open) | void setOpen (const bool open) | ||||
| { | { | ||||
| if (isOpen_ != open) | |||||
| if (sectionIsOpen != open) | |||||
| { | { | ||||
| isOpen_ = open; | |||||
| sectionIsOpen = open; | |||||
| for (int i = 0; i < getNumChildComponents(); ++i) | |||||
| { | |||||
| PropertyComponent* pec = dynamic_cast <PropertyComponent*> (getChildComponent (i)); | |||||
| for (int i = propertyComps.size(); --i >= 0;) | |||||
| propertyComps.getUnchecked(i)->setVisible (open); | |||||
| if (pec != 0) | |||||
| pec->setVisible (open); | |||||
| } | |||||
| // (unable to use the syntax findParentComponentOfClass <DragAndDropContainer> () because of a VC6 compiler bug) | |||||
| PropertyPanel* const pp = findParentComponentOfClass ((PropertyPanel*) 0); | PropertyPanel* const pp = findParentComponentOfClass ((PropertyPanel*) 0); | ||||
| if (pp != 0) | if (pp != 0) | ||||
| @@ -145,22 +106,13 @@ public: | |||||
| bool isOpen() const | bool isOpen() const | ||||
| { | { | ||||
| return isOpen_; | |||||
| return sectionIsOpen; | |||||
| } | } | ||||
| void refreshAll() const | void refreshAll() const | ||||
| { | { | ||||
| for (int i = 0; i < getNumChildComponents(); ++i) | |||||
| { | |||||
| PropertyComponent* pec = dynamic_cast <PropertyComponent*> (getChildComponent (i)); | |||||
| if (pec != 0) | |||||
| pec->refresh(); | |||||
| } | |||||
| } | |||||
| void mouseDown (const MouseEvent&) | |||||
| { | |||||
| for (int i = propertyComps.size(); --i >= 0;) | |||||
| propertyComps.getUnchecked (i)->refresh(); | |||||
| } | } | ||||
| void mouseUp (const MouseEvent& e) | void mouseUp (const MouseEvent& e) | ||||
| @@ -181,45 +133,65 @@ public: | |||||
| } | } | ||||
| private: | private: | ||||
| OwnedArray <PropertyComponent> propertyComps; | |||||
| int titleHeight; | int titleHeight; | ||||
| bool isOpen_; | |||||
| bool sectionIsOpen; | |||||
| PropertySectionComponent (const PropertySectionComponent&); | PropertySectionComponent (const PropertySectionComponent&); | ||||
| PropertySectionComponent& operator= (const PropertySectionComponent&); | PropertySectionComponent& operator= (const PropertySectionComponent&); | ||||
| }; | }; | ||||
| void PropertyPanel::PropertyHolderComponent::updateLayout (const int width) | |||||
| //============================================================================== | |||||
| class PropertyPanel::PropertyHolderComponent : public Component | |||||
| { | { | ||||
| int y = 0; | |||||
| public: | |||||
| PropertyHolderComponent() {} | |||||
| for (int i = getNumChildComponents(); --i >= 0;) | |||||
| void paint (Graphics&) {} | |||||
| void updateLayout (int width) | |||||
| { | { | ||||
| PropertySectionComponent* const section | |||||
| = dynamic_cast <PropertySectionComponent*> (getChildComponent (i)); | |||||
| int y = 0; | |||||
| if (section != 0) | |||||
| for (int i = 0; i < sections.size(); ++i) | |||||
| { | { | ||||
| const int prefH = section->getPreferredHeight(); | |||||
| section->setBounds (0, y, width, prefH); | |||||
| y += prefH; | |||||
| PropertySectionComponent* const section = sections.getUnchecked(i); | |||||
| section->setBounds (0, y, width, section->getPreferredHeight()); | |||||
| y = section->getBottom(); | |||||
| } | } | ||||
| setSize (width, y); | |||||
| repaint(); | |||||
| } | } | ||||
| setSize (width, y); | |||||
| repaint(); | |||||
| } | |||||
| void refreshAll() const | |||||
| { | |||||
| for (int i = 0; i < sections.size(); ++i) | |||||
| sections.getUnchecked(i)->refreshAll(); | |||||
| } | |||||
| void PropertyPanel::PropertyHolderComponent::refreshAll() const | |||||
| { | |||||
| for (int i = getNumChildComponents(); --i >= 0;) | |||||
| void clear() | |||||
| { | { | ||||
| PropertySectionComponent* const section | |||||
| = dynamic_cast <PropertySectionComponent*> (getChildComponent (i)); | |||||
| sections.clear(); | |||||
| } | |||||
| if (section != 0) | |||||
| section->refreshAll(); | |||||
| void addSection (PropertySectionComponent* newSection) | |||||
| { | |||||
| sections.add (newSection); | |||||
| addAndMakeVisible (newSection, 0); | |||||
| } | } | ||||
| } | |||||
| int getNumSections() const throw() { return sections.size(); } | |||||
| PropertySectionComponent* getSection (const int index) const { return sections [index]; } | |||||
| private: | |||||
| OwnedArray<PropertySectionComponent> sections; | |||||
| PropertyHolderComponent (const PropertyHolderComponent&); | |||||
| PropertyHolderComponent& operator= (const PropertyHolderComponent&); | |||||
| }; | |||||
| //============================================================================== | //============================================================================== | ||||
| PropertyPanel::PropertyPanel() | PropertyPanel::PropertyPanel() | ||||
| @@ -239,7 +211,7 @@ PropertyPanel::~PropertyPanel() | |||||
| //============================================================================== | //============================================================================== | ||||
| void PropertyPanel::paint (Graphics& g) | void PropertyPanel::paint (Graphics& g) | ||||
| { | { | ||||
| if (propertyHolderComponent->getNumChildComponents() == 0) | |||||
| if (propertyHolderComponent->getNumSections() == 0) | |||||
| { | { | ||||
| g.setColour (Colours::black.withAlpha (0.5f)); | g.setColour (Colours::black.withAlpha (0.5f)); | ||||
| g.setFont (14.0f); | g.setFont (14.0f); | ||||
| @@ -257,21 +229,19 @@ void PropertyPanel::resized() | |||||
| //============================================================================== | //============================================================================== | ||||
| void PropertyPanel::clear() | void PropertyPanel::clear() | ||||
| { | { | ||||
| if (propertyHolderComponent->getNumChildComponents() > 0) | |||||
| if (propertyHolderComponent->getNumSections() > 0) | |||||
| { | { | ||||
| propertyHolderComponent->deleteAllChildren(); | |||||
| propertyHolderComponent->clear(); | |||||
| repaint(); | repaint(); | ||||
| } | } | ||||
| } | } | ||||
| void PropertyPanel::addProperties (const Array <PropertyComponent*>& newProperties) | void PropertyPanel::addProperties (const Array <PropertyComponent*>& newProperties) | ||||
| { | { | ||||
| if (propertyHolderComponent->getNumChildComponents() == 0) | |||||
| if (propertyHolderComponent->getNumSections() == 0) | |||||
| repaint(); | repaint(); | ||||
| propertyHolderComponent->addAndMakeVisible (new PropertySectionComponent (String::empty, | |||||
| newProperties, | |||||
| true), 0); | |||||
| propertyHolderComponent->addSection (new PropertySectionComponent (String::empty, newProperties, true)); | |||||
| updatePropHolderLayout(); | updatePropHolderLayout(); | ||||
| } | } | ||||
| @@ -281,13 +251,10 @@ void PropertyPanel::addSection (const String& sectionTitle, | |||||
| { | { | ||||
| jassert (sectionTitle.isNotEmpty()); | jassert (sectionTitle.isNotEmpty()); | ||||
| if (propertyHolderComponent->getNumChildComponents() == 0) | |||||
| if (propertyHolderComponent->getNumSections() == 0) | |||||
| repaint(); | repaint(); | ||||
| propertyHolderComponent->addAndMakeVisible (new PropertySectionComponent (sectionTitle, | |||||
| newProperties, | |||||
| shouldBeOpen), 0); | |||||
| propertyHolderComponent->addSection (new PropertySectionComponent (sectionTitle, newProperties, shouldBeOpen)); | |||||
| updatePropHolderLayout(); | updatePropHolderLayout(); | ||||
| } | } | ||||
| @@ -314,11 +281,11 @@ const StringArray PropertyPanel::getSectionNames() const | |||||
| { | { | ||||
| StringArray s; | StringArray s; | ||||
| for (int i = 0; i < propertyHolderComponent->getNumChildComponents(); ++i) | |||||
| for (int i = 0; i < propertyHolderComponent->getNumSections(); ++i) | |||||
| { | { | ||||
| PropertySectionComponent* const section = dynamic_cast <PropertySectionComponent*> (propertyHolderComponent->getChildComponent (i)); | |||||
| PropertySectionComponent* const section = propertyHolderComponent->getSection (i); | |||||
| if (section != 0 && section->getName().isNotEmpty()) | |||||
| if (section->getName().isNotEmpty()) | |||||
| s.add (section->getName()); | s.add (section->getName()); | ||||
| } | } | ||||
| @@ -329,11 +296,11 @@ bool PropertyPanel::isSectionOpen (const int sectionIndex) const | |||||
| { | { | ||||
| int index = 0; | int index = 0; | ||||
| for (int i = 0; i < propertyHolderComponent->getNumChildComponents(); ++i) | |||||
| for (int i = 0; i < propertyHolderComponent->getNumSections(); ++i) | |||||
| { | { | ||||
| PropertySectionComponent* const section = dynamic_cast <PropertySectionComponent*> (propertyHolderComponent->getChildComponent (i)); | |||||
| PropertySectionComponent* const section = propertyHolderComponent->getSection (i); | |||||
| if (section != 0 && section->getName().isNotEmpty()) | |||||
| if (section->getName().isNotEmpty()) | |||||
| { | { | ||||
| if (index == sectionIndex) | if (index == sectionIndex) | ||||
| return section->isOpen(); | return section->isOpen(); | ||||
| @@ -349,11 +316,11 @@ void PropertyPanel::setSectionOpen (const int sectionIndex, const bool shouldBeO | |||||
| { | { | ||||
| int index = 0; | int index = 0; | ||||
| for (int i = 0; i < propertyHolderComponent->getNumChildComponents(); ++i) | |||||
| for (int i = 0; i < propertyHolderComponent->getNumSections(); ++i) | |||||
| { | { | ||||
| PropertySectionComponent* const section = dynamic_cast <PropertySectionComponent*> (propertyHolderComponent->getChildComponent (i)); | |||||
| PropertySectionComponent* const section = propertyHolderComponent->getSection (i); | |||||
| if (section != 0 && section->getName().isNotEmpty()) | |||||
| if (section->getName().isNotEmpty()) | |||||
| { | { | ||||
| if (index == sectionIndex) | if (index == sectionIndex) | ||||
| { | { | ||||
| @@ -370,11 +337,11 @@ void PropertyPanel::setSectionEnabled (const int sectionIndex, const bool should | |||||
| { | { | ||||
| int index = 0; | int index = 0; | ||||
| for (int i = 0; i < propertyHolderComponent->getNumChildComponents(); ++i) | |||||
| for (int i = 0; i < propertyHolderComponent->getNumSections(); ++i) | |||||
| { | { | ||||
| PropertySectionComponent* const section = dynamic_cast <PropertySectionComponent*> (propertyHolderComponent->getChildComponent (i)); | |||||
| PropertySectionComponent* const section = propertyHolderComponent->getSection (i); | |||||
| if (section != 0 && section->getName().isNotEmpty()) | |||||
| if (section->getName().isNotEmpty()) | |||||
| { | { | ||||
| if (index == sectionIndex) | if (index == sectionIndex) | ||||
| { | { | ||||
| @@ -66,6 +66,7 @@ public: | |||||
| of (0, 0). | of (0, 0). | ||||
| */ | */ | ||||
| virtual void setOrigin (int x, int y) = 0; | virtual void setOrigin (int x, int y) = 0; | ||||
| virtual void addTransform (const AffineTransform& transform) = 0; | |||||
| virtual bool clipToRectangle (const Rectangle<int>& r) = 0; | virtual bool clipToRectangle (const Rectangle<int>& r) = 0; | ||||
| virtual bool clipToRectangleList (const RectangleList& clipRegion) = 0; | virtual bool clipToRectangleList (const RectangleList& clipRegion) = 0; | ||||
| @@ -112,6 +112,12 @@ void LowLevelGraphicsPostScriptRenderer::setOrigin (int x, int y) | |||||
| } | } | ||||
| } | } | ||||
| void LowLevelGraphicsPostScriptRenderer::addTransform (const AffineTransform& /*transform*/) | |||||
| { | |||||
| //xxx | |||||
| jassertfalse; | |||||
| } | |||||
| bool LowLevelGraphicsPostScriptRenderer::clipToRectangle (const Rectangle<int>& r) | bool LowLevelGraphicsPostScriptRenderer::clipToRectangle (const Rectangle<int>& r) | ||||
| { | { | ||||
| needToClip = true; | needToClip = true; | ||||
| @@ -49,6 +49,7 @@ public: | |||||
| //============================================================================== | //============================================================================== | ||||
| bool isVectorDevice() const; | bool isVectorDevice() const; | ||||
| void setOrigin (int x, int y); | void setOrigin (int x, int y); | ||||
| void addTransform (const AffineTransform& transform); | |||||
| bool clipToRectangle (const Rectangle<int>& r); | bool clipToRectangle (const Rectangle<int>& r); | ||||
| bool clipToRectangleList (const RectangleList& clipRegion); | bool clipToRectangleList (const RectangleList& clipRegion); | ||||
| @@ -830,19 +830,17 @@ private: | |||||
| //============================================================================== | //============================================================================== | ||||
| void render4PixelAverage (PixelRGB* const dest, const uint8* src, const int subPixelX, const int subPixelY) throw() | void render4PixelAverage (PixelRGB* const dest, const uint8* src, const int subPixelX, const int subPixelY) throw() | ||||
| { | { | ||||
| uint32 c[4] = { 256 * 128, 256 * 128, 256 * 128, 256 * 128 }; | |||||
| uint32 c[3] = { 256 * 128, 256 * 128, 256 * 128 }; | |||||
| uint32 weight = (256 - subPixelX) * (256 - subPixelY); | uint32 weight = (256 - subPixelX) * (256 - subPixelY); | ||||
| c[0] += weight * src[0]; | c[0] += weight * src[0]; | ||||
| c[1] += weight * src[1]; | c[1] += weight * src[1]; | ||||
| c[2] += weight * src[2]; | c[2] += weight * src[2]; | ||||
| c[3] += weight * src[3]; | |||||
| weight = subPixelX * (256 - subPixelY); | weight = subPixelX * (256 - subPixelY); | ||||
| c[0] += weight * src[4]; | |||||
| c[1] += weight * src[5]; | |||||
| c[2] += weight * src[6]; | |||||
| c[3] += weight * src[7]; | |||||
| c[0] += weight * src[3]; | |||||
| c[1] += weight * src[4]; | |||||
| c[2] += weight * src[5]; | |||||
| src += this->srcData.lineStride; | src += this->srcData.lineStride; | ||||
| @@ -850,60 +848,56 @@ private: | |||||
| c[0] += weight * src[0]; | c[0] += weight * src[0]; | ||||
| c[1] += weight * src[1]; | c[1] += weight * src[1]; | ||||
| c[2] += weight * src[2]; | c[2] += weight * src[2]; | ||||
| c[3] += weight * src[3]; | |||||
| weight = subPixelX * subPixelY; | weight = subPixelX * subPixelY; | ||||
| c[0] += weight * src[4]; | |||||
| c[1] += weight * src[5]; | |||||
| c[2] += weight * src[6]; | |||||
| c[3] += weight * src[7]; | |||||
| c[0] += weight * src[3]; | |||||
| c[1] += weight * src[4]; | |||||
| c[2] += weight * src[5]; | |||||
| dest->setARGB ((uint8) (c[PixelARGB::indexA] >> 16), | |||||
| (uint8) (c[PixelARGB::indexR] >> 16), | |||||
| (uint8) (c[PixelARGB::indexG] >> 16), | |||||
| (uint8) (c[PixelARGB::indexB] >> 16)); | |||||
| dest->setARGB ((uint8) 255, | |||||
| (uint8) (c[PixelRGB::indexR] >> 16), | |||||
| (uint8) (c[PixelRGB::indexG] >> 16), | |||||
| (uint8) (c[PixelRGB::indexB] >> 16)); | |||||
| } | } | ||||
| void render2PixelAverageX (PixelRGB* const dest, const uint8* src, const int subPixelX, const int alpha) throw() | |||||
| void render2PixelAverageX (PixelRGB* const dest, const uint8* src, const int subPixelX, const int /*alpha*/) throw() | |||||
| { | { | ||||
| uint32 c[3] = { 256 * 128, 256 * 128, 256 * 128 }; | |||||
| uint32 c[3] = { 128, 128, 128 }; | |||||
| uint32 weight = (256 - subPixelX) * alpha; | |||||
| uint32 weight = (256 - subPixelX); | |||||
| c[0] += weight * src[0]; | c[0] += weight * src[0]; | ||||
| c[1] += weight * src[1]; | c[1] += weight * src[1]; | ||||
| c[2] += weight * src[2]; | c[2] += weight * src[2]; | ||||
| weight = subPixelX * alpha; | |||||
| c[0] += weight * src[3]; | |||||
| c[1] += weight * src[4]; | |||||
| c[2] += weight * src[5]; | |||||
| c[0] += subPixelX * src[3]; | |||||
| c[1] += subPixelX * src[4]; | |||||
| c[2] += subPixelX * src[5]; | |||||
| dest->setARGB ((uint8) 255, | dest->setARGB ((uint8) 255, | ||||
| (uint8) (c[PixelRGB::indexR] >> 16), | |||||
| (uint8) (c[PixelRGB::indexG] >> 16), | |||||
| (uint8) (c[PixelRGB::indexB] >> 16)); | |||||
| (uint8) (c[PixelRGB::indexR] >> 8), | |||||
| (uint8) (c[PixelRGB::indexG] >> 8), | |||||
| (uint8) (c[PixelRGB::indexB] >> 8)); | |||||
| } | } | ||||
| void render2PixelAverageY (PixelRGB* const dest, const uint8* src, const int subPixelY, const int alpha) throw() | |||||
| void render2PixelAverageY (PixelRGB* const dest, const uint8* src, const int subPixelY, const int /*alpha*/) throw() | |||||
| { | { | ||||
| uint32 c[3] = { 256 * 128, 256 * 128, 256 * 128 }; | |||||
| uint32 c[3] = { 128, 128, 128 }; | |||||
| uint32 weight = (256 - subPixelY) * alpha; | |||||
| uint32 weight = (256 - subPixelY); | |||||
| c[0] += weight * src[0]; | c[0] += weight * src[0]; | ||||
| c[1] += weight * src[1]; | c[1] += weight * src[1]; | ||||
| c[2] += weight * src[2]; | c[2] += weight * src[2]; | ||||
| src += this->srcData.lineStride; | src += this->srcData.lineStride; | ||||
| weight = subPixelY * alpha; | |||||
| c[0] += weight * src[0]; | |||||
| c[1] += weight * src[1]; | |||||
| c[2] += weight * src[2]; | |||||
| c[0] += subPixelY * src[0]; | |||||
| c[1] += subPixelY * src[1]; | |||||
| c[2] += subPixelY * src[2]; | |||||
| dest->setARGB ((uint8) 255, | dest->setARGB ((uint8) 255, | ||||
| (uint8) (c[PixelRGB::indexR] >> 16), | |||||
| (uint8) (c[PixelRGB::indexG] >> 16), | |||||
| (uint8) (c[PixelRGB::indexB] >> 16)); | |||||
| (uint8) (c[PixelRGB::indexR] >> 8), | |||||
| (uint8) (c[PixelRGB::indexG] >> 8), | |||||
| (uint8) (c[PixelRGB::indexB] >> 8)); | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -1796,38 +1790,67 @@ class LowLevelGraphicsSoftwareRenderer::SavedState | |||||
| public: | public: | ||||
| SavedState (const Rectangle<int>& clip_, const int xOffset_, const int yOffset_) | SavedState (const Rectangle<int>& clip_, const int xOffset_, const int yOffset_) | ||||
| : clip (new SoftwareRendererClasses::ClipRegion_RectangleList (clip_)), | : clip (new SoftwareRendererClasses::ClipRegion_RectangleList (clip_)), | ||||
| xOffset (xOffset_), yOffset (yOffset_), interpolationQuality (Graphics::mediumResamplingQuality) | |||||
| xOffset (xOffset_), yOffset (yOffset_), isOnlyTranslated (true), interpolationQuality (Graphics::mediumResamplingQuality) | |||||
| { | { | ||||
| } | } | ||||
| SavedState (const RectangleList& clip_, const int xOffset_, const int yOffset_) | SavedState (const RectangleList& clip_, const int xOffset_, const int yOffset_) | ||||
| : clip (new SoftwareRendererClasses::ClipRegion_RectangleList (clip_)), | : clip (new SoftwareRendererClasses::ClipRegion_RectangleList (clip_)), | ||||
| xOffset (xOffset_), yOffset (yOffset_), interpolationQuality (Graphics::mediumResamplingQuality) | |||||
| xOffset (xOffset_), yOffset (yOffset_), isOnlyTranslated (true), interpolationQuality (Graphics::mediumResamplingQuality) | |||||
| { | { | ||||
| } | } | ||||
| SavedState (const SavedState& other) | SavedState (const SavedState& other) | ||||
| : clip (other.clip), xOffset (other.xOffset), yOffset (other.yOffset), font (other.font), | |||||
| fillType (other.fillType), interpolationQuality (other.interpolationQuality) | |||||
| : clip (other.clip), complexTransform (other.complexTransform), xOffset (other.xOffset), yOffset (other.yOffset), | |||||
| isOnlyTranslated (other.isOnlyTranslated), font (other.font), fillType (other.fillType), interpolationQuality (other.interpolationQuality) | |||||
| { | { | ||||
| } | } | ||||
| ~SavedState() | |||||
| void setOrigin (const int x, const int y) throw() | |||||
| { | { | ||||
| if (isOnlyTranslated) | |||||
| { | |||||
| xOffset += x; | |||||
| yOffset += y; | |||||
| } | |||||
| else | |||||
| { | |||||
| complexTransform = getTransformWith (AffineTransform::translation ((float) x, (float) y)); | |||||
| } | |||||
| } | } | ||||
| void setOrigin (const int x, const int y) throw() | |||||
| void addTransform (const AffineTransform& t) | |||||
| { | { | ||||
| xOffset += x; | |||||
| yOffset += y; | |||||
| if ((! isOnlyTranslated) | |||||
| || (! t.isOnlyTranslation()) | |||||
| || (int) (t.getTranslationX() * 256.0f) != 0 | |||||
| || (int) (t.getTranslationY() * 256.0f) != 0) | |||||
| { | |||||
| complexTransform = getTransformWith (t); | |||||
| isOnlyTranslated = false; | |||||
| } | |||||
| else | |||||
| { | |||||
| xOffset += (int) t.getTranslationX(); | |||||
| yOffset += (int) t.getTranslationY(); | |||||
| } | |||||
| } | } | ||||
| bool clipToRectangle (const Rectangle<int>& r) | bool clipToRectangle (const Rectangle<int>& r) | ||||
| { | { | ||||
| if (clip != 0) | if (clip != 0) | ||||
| { | { | ||||
| cloneClipIfMultiplyReferenced(); | |||||
| clip = clip->clipToRectangle (r.translated (xOffset, yOffset)); | |||||
| if (isOnlyTranslated) | |||||
| { | |||||
| cloneClipIfMultiplyReferenced(); | |||||
| clip = clip->clipToRectangle (r.translated (xOffset, yOffset)); | |||||
| } | |||||
| else | |||||
| { | |||||
| Path p; | |||||
| p.addRectangle (r); | |||||
| clipToPath (p, AffineTransform::identity); | |||||
| } | |||||
| } | } | ||||
| return clip != 0; | return clip != 0; | ||||
| @@ -1837,11 +1860,17 @@ public: | |||||
| { | { | ||||
| if (clip != 0) | if (clip != 0) | ||||
| { | { | ||||
| cloneClipIfMultiplyReferenced(); | |||||
| RectangleList offsetList (r); | |||||
| offsetList.offsetAll (xOffset, yOffset); | |||||
| clip = clip->clipToRectangleList (offsetList); | |||||
| if (isOnlyTranslated) | |||||
| { | |||||
| cloneClipIfMultiplyReferenced(); | |||||
| RectangleList offsetList (r); | |||||
| offsetList.offsetAll (xOffset, yOffset); | |||||
| clip = clip->clipToRectangleList (offsetList); | |||||
| } | |||||
| else | |||||
| { | |||||
| clipToPath (r.toPath(), AffineTransform::identity); | |||||
| } | |||||
| } | } | ||||
| return clip != 0; | return clip != 0; | ||||
| @@ -1851,8 +1880,17 @@ public: | |||||
| { | { | ||||
| if (clip != 0) | if (clip != 0) | ||||
| { | { | ||||
| cloneClipIfMultiplyReferenced(); | |||||
| clip = clip->excludeClipRectangle (r.translated (xOffset, yOffset)); | |||||
| if (isOnlyTranslated) | |||||
| { | |||||
| cloneClipIfMultiplyReferenced(); | |||||
| clip = clip->excludeClipRectangle (r.translated (xOffset, yOffset)); | |||||
| } | |||||
| else | |||||
| { | |||||
| RectangleList all (getClipBounds()); | |||||
| all.subtract (r); | |||||
| return clipToRectangleList (all); | |||||
| } | |||||
| } | } | ||||
| return clip != 0; | return clip != 0; | ||||
| @@ -1863,7 +1901,7 @@ public: | |||||
| if (clip != 0) | if (clip != 0) | ||||
| { | { | ||||
| cloneClipIfMultiplyReferenced(); | cloneClipIfMultiplyReferenced(); | ||||
| clip = clip->clipToPath (p, transform.translated ((float) xOffset, (float) yOffset)); | |||||
| clip = clip->clipToPath (p, getTransformWith (transform)); | |||||
| } | } | ||||
| } | } | ||||
| @@ -1874,7 +1912,7 @@ public: | |||||
| if (image.hasAlphaChannel()) | if (image.hasAlphaChannel()) | ||||
| { | { | ||||
| cloneClipIfMultiplyReferenced(); | cloneClipIfMultiplyReferenced(); | ||||
| clip = clip->clipToImageAlpha (image, t.translated ((float) xOffset, (float) yOffset), | |||||
| clip = clip->clipToImageAlpha (image, getTransformWith (t), | |||||
| interpolationQuality != Graphics::lowResamplingQuality); | interpolationQuality != Graphics::lowResamplingQuality); | ||||
| } | } | ||||
| else | else | ||||
| @@ -1888,12 +1926,28 @@ public: | |||||
| bool clipRegionIntersects (const Rectangle<int>& r) const | bool clipRegionIntersects (const Rectangle<int>& r) const | ||||
| { | { | ||||
| return clip != 0 && clip->clipRegionIntersects (r.translated (xOffset, yOffset)); | |||||
| if (clip != 0) | |||||
| { | |||||
| if (isOnlyTranslated) | |||||
| return clip->clipRegionIntersects (r.translated (xOffset, yOffset)); | |||||
| else | |||||
| return getClipBounds().intersects (r); | |||||
| } | |||||
| return false; | |||||
| } | } | ||||
| const Rectangle<int> getClipBounds() const | const Rectangle<int> getClipBounds() const | ||||
| { | { | ||||
| return clip == 0 ? Rectangle<int>() : clip->getClipBounds().translated (-xOffset, -yOffset); | |||||
| if (clip != 0) | |||||
| { | |||||
| if (isOnlyTranslated) | |||||
| return clip->getClipBounds().translated (-xOffset, -yOffset); | |||||
| else | |||||
| return clip->getClipBounds().toFloat().transformed (getTransform().inverted()).getSmallestIntegerContainer(); | |||||
| } | |||||
| return Rectangle<int>(); | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -1901,18 +1955,27 @@ public: | |||||
| { | { | ||||
| if (clip != 0) | if (clip != 0) | ||||
| { | { | ||||
| if (fillType.isColour()) | |||||
| if (isOnlyTranslated) | |||||
| { | { | ||||
| Image::BitmapData destData (image, true); | |||||
| clip->fillRectWithColour (destData, r.translated (xOffset, yOffset), fillType.colour.getPixelARGB(), replaceContents); | |||||
| if (fillType.isColour()) | |||||
| { | |||||
| Image::BitmapData destData (image, true); | |||||
| clip->fillRectWithColour (destData, r.translated (xOffset, yOffset), fillType.colour.getPixelARGB(), replaceContents); | |||||
| } | |||||
| else | |||||
| { | |||||
| const Rectangle<int> totalClip (clip->getClipBounds()); | |||||
| const Rectangle<int> clipped (totalClip.getIntersection (r.translated (xOffset, yOffset))); | |||||
| if (! clipped.isEmpty()) | |||||
| fillShape (image, new SoftwareRendererClasses::ClipRegion_RectangleList (clipped), false); | |||||
| } | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| const Rectangle<int> totalClip (clip->getClipBounds()); | |||||
| const Rectangle<int> clipped (totalClip.getIntersection (r.translated (xOffset, yOffset))); | |||||
| if (! clipped.isEmpty()) | |||||
| fillShape (image, new SoftwareRendererClasses::ClipRegion_RectangleList (clipped), false); | |||||
| Path p; | |||||
| p.addRectangle (r); | |||||
| fillPath (image, p, AffineTransform::identity); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1921,18 +1984,27 @@ public: | |||||
| { | { | ||||
| if (clip != 0) | if (clip != 0) | ||||
| { | { | ||||
| if (fillType.isColour()) | |||||
| if (isOnlyTranslated) | |||||
| { | { | ||||
| Image::BitmapData destData (image, true); | |||||
| clip->fillRectWithColour (destData, r.translated ((float) xOffset, (float) yOffset), fillType.colour.getPixelARGB()); | |||||
| if (fillType.isColour()) | |||||
| { | |||||
| Image::BitmapData destData (image, true); | |||||
| clip->fillRectWithColour (destData, r.translated ((float) xOffset, (float) yOffset), fillType.colour.getPixelARGB()); | |||||
| } | |||||
| else | |||||
| { | |||||
| const Rectangle<float> totalClip (clip->getClipBounds().toFloat()); | |||||
| const Rectangle<float> clipped (totalClip.getIntersection (r.translated ((float) xOffset, (float) yOffset))); | |||||
| if (! clipped.isEmpty()) | |||||
| fillShape (image, new SoftwareRendererClasses::ClipRegion_EdgeTable (clipped), false); | |||||
| } | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| const Rectangle<float> totalClip (clip->getClipBounds().toFloat()); | |||||
| const Rectangle<float> clipped (totalClip.getIntersection (r.translated ((float) xOffset, (float) yOffset))); | |||||
| if (! clipped.isEmpty()) | |||||
| fillShape (image, new SoftwareRendererClasses::ClipRegion_EdgeTable (clipped), false); | |||||
| Path p; | |||||
| p.addRectangle (r); | |||||
| fillPath (image, p, AffineTransform::identity); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1940,11 +2012,13 @@ public: | |||||
| void fillPath (Image& image, const Path& path, const AffineTransform& transform) | void fillPath (Image& image, const Path& path, const AffineTransform& transform) | ||||
| { | { | ||||
| if (clip != 0) | if (clip != 0) | ||||
| fillShape (image, new SoftwareRendererClasses::ClipRegion_EdgeTable (clip->getClipBounds(), path, transform.translated ((float) xOffset, (float) yOffset)), false); | |||||
| fillShape (image, new SoftwareRendererClasses::ClipRegion_EdgeTable (clip->getClipBounds(), path, getTransformWith (transform)), false); | |||||
| } | } | ||||
| void fillEdgeTable (Image& image, const EdgeTable& edgeTable, const float x, const int y) | void fillEdgeTable (Image& image, const EdgeTable& edgeTable, const float x, const int y) | ||||
| { | { | ||||
| jassert (isOnlyTranslated); | |||||
| if (clip != 0) | if (clip != 0) | ||||
| { | { | ||||
| SoftwareRendererClasses::ClipRegion_EdgeTable* edgeTableClip = new SoftwareRendererClasses::ClipRegion_EdgeTable (edgeTable); | SoftwareRendererClasses::ClipRegion_EdgeTable* edgeTableClip = new SoftwareRendererClasses::ClipRegion_EdgeTable (edgeTable); | ||||
| @@ -1970,7 +2044,7 @@ public: | |||||
| ColourGradient g2 (*(fillType.gradient)); | ColourGradient g2 (*(fillType.gradient)); | ||||
| g2.multiplyOpacity (fillType.getOpacity()); | g2.multiplyOpacity (fillType.getOpacity()); | ||||
| AffineTransform transform (fillType.transform.translated (xOffset - 0.5f, yOffset - 0.5f)); | |||||
| AffineTransform transform (getTransformWith (fillType.transform).translated (-0.5f, -0.5f)); | |||||
| const bool isIdentity = transform.isOnlyTranslation(); | const bool isIdentity = transform.isOnlyTranslation(); | ||||
| @@ -1998,7 +2072,7 @@ public: | |||||
| //============================================================================== | //============================================================================== | ||||
| void renderImage (Image& destImage, const Image& sourceImage, const AffineTransform& t, const SoftwareRendererClasses::ClipRegionBase* const tiledFillClipRegion) | void renderImage (Image& destImage, const Image& sourceImage, const AffineTransform& t, const SoftwareRendererClasses::ClipRegionBase* const tiledFillClipRegion) | ||||
| { | { | ||||
| const AffineTransform transform (t.translated ((float) xOffset, (float) yOffset)); | |||||
| const AffineTransform transform (getTransformWith (t)); | |||||
| const Image::BitmapData destData (destImage, true); | const Image::BitmapData destData (destImage, true); | ||||
| const Image::BitmapData srcData (sourceImage, false); | const Image::BitmapData srcData (sourceImage, false); | ||||
| @@ -2055,7 +2129,14 @@ public: | |||||
| //============================================================================== | //============================================================================== | ||||
| SoftwareRendererClasses::ClipRegionBase::Ptr clip; | SoftwareRendererClasses::ClipRegionBase::Ptr clip; | ||||
| private: | |||||
| AffineTransform complexTransform; | |||||
| int xOffset, yOffset; | int xOffset, yOffset; | ||||
| public: | |||||
| bool isOnlyTranslated; | |||||
| Font font; | Font font; | ||||
| FillType fillType; | FillType fillType; | ||||
| Graphics::ResamplingQuality interpolationQuality; | Graphics::ResamplingQuality interpolationQuality; | ||||
| @@ -2067,6 +2148,22 @@ private: | |||||
| clip = clip->clone(); | clip = clip->clone(); | ||||
| } | } | ||||
| const AffineTransform getTransform() const | |||||
| { | |||||
| if (isOnlyTranslated) | |||||
| return AffineTransform::translation ((float) xOffset, (float) yOffset); | |||||
| return complexTransform; | |||||
| } | |||||
| const AffineTransform getTransformWith (const AffineTransform& userTransform) const | |||||
| { | |||||
| if (isOnlyTranslated) | |||||
| return userTransform.translated ((float) xOffset, (float) yOffset); | |||||
| return userTransform.followedBy (complexTransform); | |||||
| } | |||||
| SavedState& operator= (const SavedState&); | SavedState& operator= (const SavedState&); | ||||
| }; | }; | ||||
| @@ -2100,6 +2197,11 @@ void LowLevelGraphicsSoftwareRenderer::setOrigin (int x, int y) | |||||
| currentState->setOrigin (x, y); | currentState->setOrigin (x, y); | ||||
| } | } | ||||
| void LowLevelGraphicsSoftwareRenderer::addTransform (const AffineTransform& transform) | |||||
| { | |||||
| currentState->addTransform (transform); | |||||
| } | |||||
| bool LowLevelGraphicsSoftwareRenderer::clipToRectangle (const Rectangle<int>& r) | bool LowLevelGraphicsSoftwareRenderer::clipToRectangle (const Rectangle<int>& r) | ||||
| { | { | ||||
| return currentState->clipToRectangle (r); | return currentState->clipToRectangle (r); | ||||
| @@ -2353,7 +2455,7 @@ void LowLevelGraphicsSoftwareRenderer::drawGlyph (int glyphNumber, const AffineT | |||||
| { | { | ||||
| Font& f = currentState->font; | Font& f = currentState->font; | ||||
| if (transform.isOnlyTranslation()) | |||||
| if (transform.isOnlyTranslation() && currentState->isOnlyTranslated) | |||||
| { | { | ||||
| GlyphCache::getInstance()->drawGlyph (*currentState, image, f, glyphNumber, | GlyphCache::getInstance()->drawGlyph (*currentState, image, f, glyphNumber, | ||||
| transform.getTranslationX(), | transform.getTranslationX(), | ||||
| @@ -49,6 +49,7 @@ public: | |||||
| //============================================================================== | //============================================================================== | ||||
| void setOrigin (int x, int y); | void setOrigin (int x, int y); | ||||
| void addTransform (const AffineTransform& transform); | |||||
| bool clipToRectangle (const Rectangle<int>& r); | bool clipToRectangle (const Rectangle<int>& r); | ||||
| bool clipToRectangleList (const RectangleList& clipRegion); | bool clipToRectangleList (const RectangleList& clipRegion); | ||||
| @@ -946,31 +946,19 @@ public: | |||||
| bool contains (const Point<int>& position, bool trueIfInAChildWindow) const | bool contains (const Point<int>& position, bool trueIfInAChildWindow) const | ||||
| { | { | ||||
| int x = position.getX(); | |||||
| int y = position.getY(); | |||||
| if (((unsigned int) x) >= (unsigned int) ww | |||||
| || ((unsigned int) y) >= (unsigned int) wh) | |||||
| if (((unsigned int) position.getX()) >= (unsigned int) ww | |||||
| || ((unsigned int) position.getY()) >= (unsigned int) wh) | |||||
| return false; | return false; | ||||
| bool inFront = false; | |||||
| for (int i = 0; i < Desktop::getInstance().getNumComponents(); ++i) | |||||
| for (int i = Desktop::getInstance().getNumComponents(); --i >= 0;) | |||||
| { | { | ||||
| Component* const c = Desktop::getInstance().getComponent (i); | Component* const c = Desktop::getInstance().getComponent (i); | ||||
| if (inFront) | |||||
| { | |||||
| if (c->contains (x + wx - c->getScreenX(), | |||||
| y + wy - c->getScreenY())) | |||||
| { | |||||
| return false; | |||||
| } | |||||
| } | |||||
| else if (c == getComponent()) | |||||
| { | |||||
| inFront = true; | |||||
| } | |||||
| if (c == getComponent()) | |||||
| break; | |||||
| if (c->contains (position + Point<int> (wx, wy) - c->getScreenPosition())) | |||||
| return false; | |||||
| } | } | ||||
| if (trueIfInAChildWindow) | if (trueIfInAChildWindow) | ||||
| @@ -988,7 +976,7 @@ public: | |||||
| return false; | return false; | ||||
| } | } | ||||
| if (! XTranslateCoordinates (display, windowH, windowH, x, y, &wx, &wy, &child)) | |||||
| if (! XTranslateCoordinates (display, windowH, windowH, position.getX(), position.getY(), &wx, &wy, &child)) | |||||
| return false; | return false; | ||||
| return child == None; | return child == None; | ||||
| @@ -180,6 +180,16 @@ public: | |||||
| lastClipRect.translate (-x, -y); | lastClipRect.translate (-x, -y); | ||||
| } | } | ||||
| void addTransform (const AffineTransform& transform) | |||||
| { | |||||
| applyTransform (AffineTransform::scale (1.0f, -1.0f) | |||||
| .translated (0, flipHeight) | |||||
| .followedBy (transform) | |||||
| .translated (0, -flipHeight) | |||||
| .scaled (1.0f, -1.0f)); | |||||
| lastClipRectIsValid = false; | |||||
| } | |||||
| bool clipToRectangle (const Rectangle<int>& r) | bool clipToRectangle (const Rectangle<int>& r) | ||||
| { | { | ||||
| CGContextClipToRect (context, CGRectMake (r.getX(), flipHeight - r.getBottom(), r.getWidth(), r.getHeight())); | CGContextClipToRect (context, CGRectMake (r.getX(), flipHeight - r.getBottom(), r.getWidth(), r.getHeight())); | ||||
| @@ -119,6 +119,12 @@ public: | |||||
| currentState->origin.addXY (x, y); | currentState->origin.addXY (x, y); | ||||
| } | } | ||||
| void addTransform (const AffineTransform& transform) | |||||
| { | |||||
| //xxx todo | |||||
| jassertfalse; | |||||
| } | |||||
| bool clipToRectangle (const Rectangle<int>& r) | bool clipToRectangle (const Rectangle<int>& r) | ||||
| { | { | ||||
| currentState->clipToRectangle (r); | currentState->clipToRectangle (r); | ||||