| @@ -42,30 +42,31 @@ public: | |||
| loadData(); | |||
| // 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 | |||
| 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.. | |||
| 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.. | |||
| 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 | |||
| // table->getHeader()->setStretchToFitActive (true); | |||
| // table.getHeader().setStretchToFitActive (true); | |||
| table->setMultipleSelectionEnabled (true); | |||
| table.setMultipleSelectionEnabled (true); | |||
| } | |||
| ~TableDemoComponent() | |||
| @@ -119,7 +120,7 @@ public: | |||
| DemoDataSorter sorter (getAttributeNameForColumnId (newSortColumnId), isForwards); | |||
| dataList->sortChildElements (sorter); | |||
| table->updateContent(); | |||
| table.updateContent(); | |||
| } | |||
| } | |||
| @@ -190,14 +191,14 @@ public: | |||
| void resized() | |||
| { | |||
| // position our table with a gap around its edge | |||
| table->setBoundsInset (BorderSize (8)); | |||
| table.setBoundsInset (BorderSize (8)); | |||
| } | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| ScopedPointer<TableListBox> table; // the table component itself | |||
| TableListBox table; // the table component itself | |||
| Font font; | |||
| 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) | |||
| { | |||
| return new KeyMappingEditorComponent (commandManager->getKeyMappings(), true); | |||
| return new KeyMappingEditorComponent (*commandManager->getKeyMappings(), true); | |||
| } | |||
| else if (pageName == aboutPage) | |||
| { | |||
| @@ -95,11 +95,11 @@ ResourceEditorPanel::ResourceEditorPanel (JucerDocument& document_) | |||
| delButton->setEnabled (false); | |||
| 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->setOutlineThickness (1); | |||
| @@ -64,7 +64,7 @@ | |||
| */ | |||
| #define JUCE_MAJOR_VERSION 1 | |||
| #define JUCE_MINOR_VERSION 52 | |||
| #define JUCE_BUILDNUMBER 89 | |||
| #define JUCE_BUILDNUMBER 90 | |||
| /** Current Juce version number. | |||
| @@ -26721,15 +26721,14 @@ public: | |||
| 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 | |||
| that part of the component isn't clipped by its parent component. Note | |||
| that this won't take into account any overlapping sibling components | |||
| which might be in the way - for that, see reallyContains() | |||
| @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 | |||
| siblings into account. | |||
| @@ -27914,6 +27913,9 @@ public: | |||
| /** If the component is valid, this deletes it and sets this pointer to null. */ | |||
| 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 | |||
| private: | |||
| @@ -28056,8 +28058,6 @@ private: | |||
| const Rectangle<int>& clipRect, const Component* const compToAvoid) 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(); | |||
| const Rectangle<int> getParentOrMainMonitorBounds() const; | |||
| @@ -28067,9 +28067,14 @@ private: | |||
| // implement its methods instead of this Component method). | |||
| 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& operator= (const Component&); | |||
| @@ -36739,6 +36744,7 @@ private: | |||
| ScrollBar horizontalScrollBar; | |||
| void updateVisibleArea(); | |||
| void deleteContentComp(); | |||
| Viewport (const Viewport&); | |||
| Viewport& operator= (const Viewport&); | |||
| @@ -37105,6 +37111,7 @@ private: | |||
| friend class PopupMenuCustomComponent; | |||
| friend class MenuBarComponent; | |||
| friend class OwnedArray <Item>; | |||
| friend class OwnedArray <ItemComponent>; | |||
| friend class ScopedPointer <Window>; | |||
| OwnedArray <Item> items; | |||
| @@ -46035,12 +46042,12 @@ public: | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| Button* missingItemsButton; | |||
| ScopedPointer<Button> missingItemsButton; | |||
| bool vertical, isEditingActive; | |||
| ToolbarItemStyle toolbarStyle; | |||
| class MissingItemsComponent; | |||
| friend class MissingItemsComponent; | |||
| Array <ToolbarItemComponent*> items; | |||
| OwnedArray <ToolbarItemComponent> items; | |||
| friend class ItemDragAndDropOverlayComponent; | |||
| 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 | |||
| with setModel(). | |||
| */ | |||
| TableListBox (const String& componentName, | |||
| TableListBoxModel* model); | |||
| TableListBox (const String& componentName = String::empty, | |||
| TableListBoxModel* model = 0); | |||
| /** Destructor. */ | |||
| ~TableListBox(); | |||
| @@ -48528,7 +48535,7 @@ public: | |||
| TableListBoxModel* getModel() const { return model; } | |||
| /** 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. | |||
| @see getHeaderHeight | |||
| @@ -52609,23 +52616,18 @@ private: | |||
| @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: | |||
| /** 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); | |||
| /** Destructor. */ | |||
| @@ -52639,9 +52641,8 @@ public: | |||
| void setColours (const Colour& mainBackground, | |||
| 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. | |||
| @@ -52686,29 +52687,24 @@ public: | |||
| void parentHierarchyChanged(); | |||
| /** @internal */ | |||
| void resized(); | |||
| /** @internal */ | |||
| void changeListenerCallback (void*); | |||
| /** @internal */ | |||
| bool mightContainSubItems(); | |||
| /** @internal */ | |||
| const String getUniqueName() const; | |||
| /** @internal */ | |||
| void buttonClicked (Button* button); | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| friend class KeyMappingTreeViewItem; | |||
| friend class KeyCategoryTreeViewItem; | |||
| friend class KeyMappingItemComponent; | |||
| friend class KeyMappingChangeButton; | |||
| KeyPressMappingSet* mappings; | |||
| KeyPressMappingSet& mappings; | |||
| TreeView tree; | |||
| 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& operator= (const KeyMappingEditorComponent&); | |||
| @@ -60143,6 +60139,7 @@ public: | |||
| of (0, 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 clipToRectangleList (const RectangleList& clipRegion) = 0; | |||
| @@ -60204,6 +60201,7 @@ public: | |||
| bool isVectorDevice() const; | |||
| void setOrigin (int x, int y); | |||
| void addTransform (const AffineTransform& transform); | |||
| bool clipToRectangle (const Rectangle<int>& r); | |||
| bool clipToRectangleList (const RectangleList& clipRegion); | |||
| @@ -60301,6 +60299,7 @@ public: | |||
| bool isVectorDevice() const; | |||
| void setOrigin (int x, int y); | |||
| void addTransform (const AffineTransform& transform); | |||
| bool clipToRectangle (const Rectangle<int>& r); | |||
| bool clipToRectangleList (const RectangleList& clipRegion); | |||
| @@ -33,7 +33,7 @@ | |||
| */ | |||
| #define JUCE_MAJOR_VERSION 1 | |||
| #define JUCE_MINOR_VERSION 52 | |||
| #define JUCE_BUILDNUMBER 89 | |||
| #define JUCE_BUILDNUMBER 90 | |||
| /** Current Juce version number. | |||
| @@ -40,13 +40,10 @@ ComboBox::ComboBox (const String& name) | |||
| isButtonDown (false), | |||
| separatorPending (false), | |||
| menuActive (false), | |||
| label (0) | |||
| noChoicesMessage (TRANS("(no choices)")) | |||
| { | |||
| noChoicesMessage = TRANS("(no choices)"); | |||
| setRepaintsOnMouseActivity (true); | |||
| lookAndFeelChanged(); | |||
| currentId.addListener (this); | |||
| } | |||
| @@ -58,7 +55,6 @@ ComboBox::~ComboBox() | |||
| PopupMenu::dismissAllActiveMenus(); | |||
| label = 0; | |||
| deleteAllChildren(); | |||
| } | |||
| //============================================================================== | |||
| @@ -429,30 +425,33 @@ void ComboBox::lookAndFeelChanged() | |||
| { | |||
| 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(); | |||
| } | |||
| @@ -465,27 +464,23 @@ void ComboBox::colourChanged() | |||
| //============================================================================== | |||
| 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)); | |||
| 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)); | |||
| used = true; | |||
| return true; | |||
| } | |||
| else if (key.isKeyCode (KeyPress::returnKey)) | |||
| { | |||
| showPopup(); | |||
| used = true; | |||
| return true; | |||
| } | |||
| return used; | |||
| return false; | |||
| } | |||
| 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*) | |||
| { | |||
| triggerAsyncUpdate(); | |||
| @@ -582,11 +569,8 @@ void ComboBox::mouseDown (const MouseEvent& e) | |||
| isButtonDown = isEnabled(); | |||
| if (isButtonDown | |||
| && (e.eventComponent == this || ! label->isEditable())) | |||
| { | |||
| if (isButtonDown && (e.eventComponent == this || ! label->isEditable())) | |||
| showPopup(); | |||
| } | |||
| } | |||
| void ComboBox::mouseDrag (const MouseEvent& e) | |||
| @@ -332,7 +332,7 @@ void Label::mouseUp (const MouseEvent& e) | |||
| { | |||
| if (editSingleClick | |||
| && e.mouseWasClicked() | |||
| && contains (e.x, e.y) | |||
| && contains (e.getPosition()) | |||
| && ! e.mods.isPopupMenu()) | |||
| { | |||
| showEditor(); | |||
| @@ -36,51 +36,37 @@ BEGIN_JUCE_NAMESPACE | |||
| //============================================================================== | |||
| static const char* const tableColumnPropertyTag = "_tableColumnID"; | |||
| class TableListRowComp : public Component, | |||
| public TooltipClient | |||
| { | |||
| public: | |||
| TableListRowComp (TableListBox& owner_) | |||
| : owner (owner_), | |||
| row (-1), | |||
| isSelected (false) | |||
| : owner (owner_), row (-1), isSelected (false) | |||
| { | |||
| } | |||
| ~TableListRowComp() | |||
| { | |||
| deleteAllChildren(); | |||
| } | |||
| void paint (Graphics& g) | |||
| { | |||
| TableListBoxModel* const model = owner.getModel(); | |||
| if (model != 0) | |||
| { | |||
| const TableHeaderComponent* const header = owner.getHeader(); | |||
| 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) | |||
| { | |||
| 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.reduceClipRegion (columnRect); | |||
| g.setOrigin (columnRect.getX(), 0); | |||
| model->paintCell (g, row, columnId, columnRect.getWidth(), columnRect.getHeight(), isSelected); | |||
| g.restoreState(); | |||
| } | |||
| } | |||
| @@ -89,79 +75,66 @@ public: | |||
| void update (const int newRow, const bool isNowSelected) | |||
| { | |||
| jassert (newRow >= 0); | |||
| if (newRow != row || isNowSelected != isSelected) | |||
| { | |||
| row = newRow; | |||
| isSelected = isNowSelected; | |||
| 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 | |||
| { | |||
| columnsWithComponents.clear(); | |||
| deleteAllChildren(); | |||
| columnComponents.clear(); | |||
| } | |||
| } | |||
| 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) | |||
| @@ -175,7 +148,7 @@ public: | |||
| { | |||
| 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) | |||
| owner.getModel()->cellClicked (row, columnId, e); | |||
| @@ -212,7 +185,7 @@ public: | |||
| { | |||
| 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) | |||
| owner.getModel()->cellClicked (row, columnId, e); | |||
| @@ -221,7 +194,7 @@ public: | |||
| 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) | |||
| owner.getModel()->cellDoubleClicked (row, columnId, e); | |||
| @@ -229,7 +202,7 @@ public: | |||
| 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) | |||
| return owner.getModel()->getCellTooltip (row, columnId); | |||
| @@ -239,24 +212,16 @@ public: | |||
| 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 | |||
| private: | |||
| TableListBox& owner; | |||
| OwnedArray<Component> columnComponents; | |||
| int row; | |||
| bool isSelected, isDragging, selectRowOnMouseUp; | |||
| BigInteger columnsWithComponents; | |||
| TableListRowComp (const TableListRowComp&); | |||
| TableListRowComp& operator= (const TableListRowComp&); | |||
| @@ -277,7 +242,7 @@ public: | |||
| if (owner.isAutoSizeMenuOptionShown()) | |||
| { | |||
| 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(); | |||
| } | |||
| @@ -286,17 +251,11 @@ public: | |||
| 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; | |||
| } | |||
| 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 | |||
| { | |||
| Rectangle<int> headerCell (header->getColumnPosition (header->getIndexOfColumnId (columnId, true))); | |||
| @@ -384,10 +342,9 @@ const Rectangle<int> TableListBox::getCellPosition (const int columnId, | |||
| if (relativeToComponentTopLeft) | |||
| 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 | |||
| @@ -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) | |||
| { | |||
| @@ -208,8 +208,8 @@ public: | |||
| The model pointer passed-in can be null, in which case you can set it later | |||
| with setModel(). | |||
| */ | |||
| TableListBox (const String& componentName, | |||
| TableListBoxModel* model); | |||
| TableListBox (const String& componentName = String::empty, | |||
| TableListBoxModel* model = 0); | |||
| /** Destructor. */ | |||
| ~TableListBox(); | |||
| @@ -224,7 +224,7 @@ public: | |||
| //============================================================================== | |||
| /** 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. | |||
| @see getHeaderHeight | |||
| @@ -281,7 +281,7 @@ Toolbar::Toolbar() | |||
| Toolbar::~Toolbar() | |||
| { | |||
| deleteAllChildren(); | |||
| items.clear(); | |||
| } | |||
| void Toolbar::setVertical (const bool shouldBeVertical) | |||
| @@ -295,13 +295,7 @@ void Toolbar::setVertical (const bool shouldBeVertical) | |||
| void Toolbar::clear() | |||
| { | |||
| for (int i = items.size(); --i >= 0;) | |||
| { | |||
| ToolbarItemComponent* const tc = items.getUnchecked(i); | |||
| items.remove (i); | |||
| delete tc; | |||
| } | |||
| items.clear(); | |||
| resized(); | |||
| } | |||
| @@ -365,14 +359,8 @@ void Toolbar::addDefaultItems (ToolbarItemFactory& factoryToUse) | |||
| 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() | |||
| @@ -672,7 +660,7 @@ void Toolbar::itemDragMove (const String&, Component* sourceComponent, int x, in | |||
| if (newIndex != currentIndex) | |||
| { | |||
| items.removeValue (tc); | |||
| items.removeObject (tc, false); | |||
| removeChildComponent (tc); | |||
| addChildComponent (tc, newIndex); | |||
| items.insert (newIndex, tc); | |||
| @@ -695,7 +683,7 @@ void Toolbar::itemDragExit (const String&, Component* sourceComponent) | |||
| { | |||
| if (isParentOf (tc)) | |||
| { | |||
| items.removeValue (tc); | |||
| items.removeObject (tc, false); | |||
| removeChildComponent (tc); | |||
| updateAllItemPositions (true); | |||
| } | |||
| @@ -294,12 +294,12 @@ public: | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| Button* missingItemsButton; | |||
| ScopedPointer<Button> missingItemsButton; | |||
| bool vertical, isEditingActive; | |||
| ToolbarItemStyle toolbarStyle; | |||
| class MissingItemsComponent; | |||
| friend class MissingItemsComponent; | |||
| Array <ToolbarItemComponent*> items; | |||
| OwnedArray <ToolbarItemComponent> items; | |||
| friend class ItemDragAndDropOverlayComponent; | |||
| static const char* const toolbarDragDescriptor; | |||
| @@ -786,36 +786,43 @@ const Rectangle<int> Component::getScreenBounds() const | |||
| 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> | |||
| 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); | |||
| if (directParent == parent) | |||
| return convertFromParentSpace (target, coordInParent); | |||
| return convertFromParentSpace (target, convertFromDistantParentSpace (parent, directParent, coordInParent)); | |||
| return convertFromParentSpace (target, convertFromDistantParentSpace (parent, *directParent, coordInParent)); | |||
| } | |||
| template <typename Type> | |||
| @@ -827,7 +834,7 @@ namespace CoordinateHelpers | |||
| return p; | |||
| if (source->isParentOf (target)) | |||
| return convertFromDistantParentSpace (source, target, p); | |||
| return convertFromDistantParentSpace (source, *target, p); | |||
| if (source->isOnDesktop()) | |||
| { | |||
| @@ -836,7 +843,7 @@ namespace CoordinateHelpers | |||
| } | |||
| else | |||
| { | |||
| p = convertToParentSpace (source, p); | |||
| p = convertToParentSpace (*source, p); | |||
| source = source->getParentComponent(); | |||
| } | |||
| } | |||
| @@ -850,12 +857,24 @@ namespace CoordinateHelpers | |||
| if (topLevelComp->isOnDesktop()) | |||
| p = topLevelComp->getPeer()->globalToLocal (p); | |||
| else | |||
| p = convertFromParentSpace (topLevelComp, p); | |||
| p = convertFromParentSpace (*topLevelComp, p); | |||
| if (topLevelComp == target) | |||
| 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;) | |||
| { | |||
| 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; | |||
| } | |||
| } | |||
| } | |||
| @@ -1129,70 +1144,50 @@ void Component::getInterceptsMouseClicks (bool& allowsClicksOnThisComponent, | |||
| 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) | |||
| { | |||
| return parentComponent_->contains (x + getX(), | |||
| y + getY()); | |||
| return parentComponent_->contains (CoordinateHelpers::convertToParentSpace (*this, point)); | |||
| } | |||
| else if (flags.hasHeavyweightPeerFlag) | |||
| { | |||
| const ComponentPeer* const peer = getPeer(); | |||
| if (peer != 0) | |||
| return peer->contains (Point<int> (x, y), true); | |||
| return peer->contains (point, true); | |||
| } | |||
| } | |||
| 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) | |||
| { | |||
| 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;) | |||
| { | |||
| 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; | |||
| @@ -1201,6 +1196,11 @@ Component* Component::getComponentAt (const int x, const int y) | |||
| 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) | |||
| { | |||
| @@ -1925,27 +1925,6 @@ const Rectangle<int> Component::getParentOrMainMonitorBounds() const | |||
| : 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, | |||
| 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 | |||
| { | |||
| result.clear(); | |||
| const Rectangle<int> unclipped (getUnclippedArea()); | |||
| const Rectangle<int> unclipped (CoordinateHelpers::getUnclippedArea (*this)); | |||
| if (! unclipped.isEmpty()) | |||
| { | |||
| @@ -728,15 +728,14 @@ public: | |||
| 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 | |||
| that part of the component isn't clipped by its parent component. Note | |||
| that this won't take into account any overlapping sibling components | |||
| which might be in the way - for that, see reallyContains() | |||
| @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 | |||
| siblings into account. | |||
| @@ -1949,6 +1948,9 @@ public: | |||
| /** If the component is valid, this deletes it and sets this pointer to null. */ | |||
| 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 | |||
| @@ -2097,8 +2099,6 @@ private: | |||
| const Rectangle<int>& clipRect, const Component* const compToAvoid) 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(); | |||
| const Rectangle<int> getParentOrMainMonitorBounds() const; | |||
| @@ -2109,9 +2109,14 @@ private: | |||
| // implement its methods instead of this Component method). | |||
| 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& operator= (const Component&); | |||
| @@ -162,8 +162,8 @@ Component* Desktop::findComponentAt (const Point<int>& screenPosition) const | |||
| { | |||
| 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: | |||
| 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), | |||
| owner (owner_), | |||
| commandID (commandID_), | |||
| @@ -75,21 +75,16 @@ public: | |||
| m.addSeparator(); | |||
| 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 | |||
| { | |||
| // + 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 | |||
| private: | |||
| @@ -113,43 +190,37 @@ private: | |||
| const CommandID commandID; | |||
| 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: | |||
| KeyMappingItemComponent (KeyMappingEditorComponent& owner_, const CommandID commandID_) | |||
| ItemComponent (KeyMappingEditorComponent& owner_, const CommandID commandID_) | |||
| : owner (owner_), commandID (commandID_) | |||
| { | |||
| setInterceptsMouseClicks (false, true); | |||
| 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) | |||
| { | |||
| 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) | |||
| @@ -157,7 +228,7 @@ public: | |||
| g.setFont (getHeight() * 0.7f); | |||
| 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(), | |||
| Justification::centredLeft, true); | |||
| } | |||
| @@ -166,33 +237,34 @@ public: | |||
| { | |||
| 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 | |||
| private: | |||
| KeyMappingEditorComponent& owner; | |||
| OwnedArray<ChangeKeyButton> keyChangeButtons; | |||
| 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: | |||
| KeyMappingTreeViewItem (KeyMappingEditorComponent& owner_, const CommandID commandID_) | |||
| MappingItem (KeyMappingEditorComponent& owner_, const CommandID commandID_) | |||
| : owner (owner_), commandID (commandID_) | |||
| { | |||
| } | |||
| @@ -203,7 +275,7 @@ public: | |||
| Component* createItemComponent() | |||
| { | |||
| return new KeyMappingItemComponent (owner, commandID); | |||
| return new ItemComponent (owner, commandID); | |||
| } | |||
| juce_UseDebuggingNewOperator | |||
| @@ -212,16 +284,16 @@ private: | |||
| KeyMappingEditorComponent& owner; | |||
| 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: | |||
| KeyCategoryTreeViewItem (KeyMappingEditorComponent& owner_, const String& name) | |||
| CategoryItem (KeyMappingEditorComponent& owner_, const String& name) | |||
| : owner (owner_), categoryName (name) | |||
| { | |||
| } | |||
| @@ -246,12 +318,12 @@ public: | |||
| { | |||
| 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) | |||
| { | |||
| if (owner.shouldCommandBeIncluded (commands[i])) | |||
| addSubItem (new KeyMappingTreeViewItem (owner, commands[i])); | |||
| addSubItem (new MappingItem (owner, commands[i])); | |||
| } | |||
| } | |||
| } | |||
| @@ -267,52 +339,99 @@ private: | |||
| KeyMappingEditorComponent& owner; | |||
| 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) | |||
| : mappings (mappingManager), | |||
| resetButton (TRANS ("reset to defaults")) | |||
| { | |||
| jassert (mappingManager != 0); // can't be null! | |||
| mappingManager->addChangeListener (this); | |||
| setLinesDrawnForSubItems (false); | |||
| treeItem = new TopLevelItem (*this); | |||
| if (showResetToDefaultButton) | |||
| { | |||
| addAndMakeVisible (&resetButton); | |||
| resetButton.addButtonListener (this); | |||
| resetButton.addButtonListener (treeItem); | |||
| } | |||
| addAndMakeVisible (&tree); | |||
| tree.setColour (TreeView::backgroundColourId, findColour (backgroundColourId)); | |||
| tree.setRootItemVisible (false); | |||
| tree.setDefaultOpenness (true); | |||
| tree.setRootItem (this); | |||
| tree.setRootItem (treeItem); | |||
| } | |||
| 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, | |||
| const Colour& textColour) | |||
| { | |||
| @@ -323,7 +442,7 @@ void KeyMappingEditorComponent::setColours (const Colour& mainBackground, | |||
| void KeyMappingEditorComponent::parentHierarchyChanged() | |||
| { | |||
| changeListenerCallback (0); | |||
| treeItem->changeListenerCallback (0); | |||
| } | |||
| void KeyMappingEditorComponent::resized() | |||
| @@ -343,157 +462,19 @@ void KeyMappingEditorComponent::resized() | |||
| 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) | |||
| { | |||
| 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) | |||
| { | |||
| 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) | |||
| @@ -38,23 +38,18 @@ | |||
| @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: | |||
| //============================================================================== | |||
| /** 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); | |||
| /** Destructor. */ | |||
| @@ -69,9 +64,8 @@ public: | |||
| void setColours (const Colour& mainBackground, | |||
| 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(); | |||
| /** @internal */ | |||
| void resized(); | |||
| /** @internal */ | |||
| void changeListenerCallback (void*); | |||
| /** @internal */ | |||
| bool mightContainSubItems(); | |||
| /** @internal */ | |||
| const String getUniqueName() const; | |||
| /** @internal */ | |||
| void buttonClicked (Button* button); | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| //============================================================================== | |||
| friend class KeyMappingTreeViewItem; | |||
| friend class KeyCategoryTreeViewItem; | |||
| friend class KeyMappingItemComponent; | |||
| friend class KeyMappingChangeButton; | |||
| KeyPressMappingSet* mappings; | |||
| KeyPressMappingSet& mappings; | |||
| TreeView tree; | |||
| 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& operator= (const KeyMappingEditorComponent&); | |||
| @@ -58,7 +58,7 @@ Viewport::Viewport (const String& componentName) | |||
| 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) | |||
| { | |||
| if (contentComp.getComponent() != newViewedComponent) | |||
| { | |||
| { | |||
| ScopedPointer<Component> oldCompDeleter (contentComp); | |||
| contentComp = 0; | |||
| } | |||
| deleteContentComp(); | |||
| contentComp = newViewedComponent; | |||
| 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) | |||
| { | |||
| @@ -264,6 +264,7 @@ private: | |||
| ScrollBar horizontalScrollBar; | |||
| void updateVisibleArea(); | |||
| void deleteContentComp(); | |||
| Viewport (const Viewport&); | |||
| Viewport& operator= (const Viewport&); | |||
| @@ -148,12 +148,17 @@ class PopupMenu::ItemComponent : public Component | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| ItemComponent (const PopupMenu::Item& itemInfo_) | |||
| ItemComponent (const PopupMenu::Item& itemInfo_, int standardItemHeight) | |||
| : itemInfo (itemInfo_), | |||
| isHighlighted (false) | |||
| { | |||
| if (itemInfo.customComp != 0) | |||
| addAndMakeVisible (itemInfo.customComp); | |||
| int itemW = 80; | |||
| int itemH = 16; | |||
| getIdealSize (itemW, itemH, standardItemHeight); | |||
| setSize (itemW, jlimit (2, 600, itemH)); | |||
| } | |||
| ~ItemComponent() | |||
| @@ -258,35 +263,68 @@ class PopupMenu::Window : public Component, | |||
| { | |||
| 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"), | |||
| owner (0), | |||
| owner (owner_), | |||
| activeSubMenu (0), | |||
| managerOfChosenCommand (0), | |||
| minimumWidth (0), | |||
| maximumNumColumns (7), | |||
| standardItemHeight (0), | |||
| managerOfChosenCommand (managerOfChosenCommand_), | |||
| componentAttachedTo (componentAttachedTo_), | |||
| componentAttachedToOriginal (componentAttachedTo_), | |||
| minimumWidth (minimumWidth_), | |||
| maximumNumColumns (maximumNumColumns_), | |||
| standardItemHeight (standardItemHeight_), | |||
| isOver (false), | |||
| hasBeenOver (false), | |||
| isDown (false), | |||
| needsToScroll (false), | |||
| dismissOnMouseUp (dismissOnMouseUp_), | |||
| hideOnExit (false), | |||
| disableMouseMoves (false), | |||
| hasAnyJuceCompHadFocus (false), | |||
| numColumns (0), | |||
| contentHeight (0), | |||
| childYOffset (0), | |||
| menuCreationTime (Time::getMillisecondCounter()), | |||
| timeEnteredCurrentChildComp (0), | |||
| scrollAcceleration (1.0) | |||
| { | |||
| menuCreationTime = lastFocused = lastScroll = Time::getMillisecondCounter(); | |||
| setWantsKeyboardFocus (true); | |||
| lastFocused = lastScroll = menuCreationTime; | |||
| setWantsKeyboardFocus (false); | |||
| setMouseClickGrabsKeyboardFocus (false); | |||
| 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); | |||
| Desktop::getInstance().addGlobalMouseListener (this); | |||
| } | |||
| ~Window() | |||
| @@ -294,69 +332,26 @@ public: | |||
| getActiveWindows().removeValue (this); | |||
| Desktop::getInstance().removeGlobalMouseListener (this); | |||
| activeSubMenu = 0; | |||
| deleteAllChildren(); | |||
| items.clear(); | |||
| } | |||
| //============================================================================== | |||
| static Window* create (const PopupMenu& menu, | |||
| const bool dismissOnMouseUp, | |||
| bool dismissOnMouseUp, | |||
| Window* const owner_, | |||
| 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, | |||
| Component* const componentAttachedTo) | |||
| Component* componentAttachedTo) | |||
| { | |||
| 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; | |||
| } | |||
| @@ -394,19 +389,6 @@ public: | |||
| : 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 | |||
| void hide (const PopupMenu::Item* const item, const bool makeInvisible) | |||
| @@ -610,8 +592,8 @@ public: | |||
| scrollAcceleration = jmin (4.0, scrollAcceleration * 1.04); | |||
| 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); | |||
| @@ -714,6 +696,7 @@ public: | |||
| private: | |||
| Window* owner; | |||
| OwnedArray <PopupMenu::ItemComponent> items; | |||
| Component::SafePointer<PopupMenu::ItemComponent> currentChild; | |||
| ScopedPointer <Window> activeSubMenu; | |||
| ApplicationCommandManager** managerOfChosenCommand; | |||
| @@ -899,13 +882,13 @@ private: | |||
| { | |||
| 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;) | |||
| { | |||
| 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); | |||
| @@ -932,9 +915,9 @@ private: | |||
| { | |||
| 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 | |||
| && m->itemInfo.itemId == itemId | |||
| @@ -1029,8 +1012,8 @@ private: | |||
| 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]; | |||
| @@ -1038,7 +1021,7 @@ private: | |||
| 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()); | |||
| y += c->getHeight(); | |||
| } | |||
| @@ -1187,14 +1170,14 @@ private: | |||
| disableTimerUntilMouseMoves(); | |||
| PopupMenu::ItemComponent* mic = 0; | |||
| bool wasLastOne = (currentChild == 0); | |||
| const int numItems = getNumChildComponents(); | |||
| const int numItems = items.size(); | |||
| for (int i = 0; i < numItems + 1; ++i) | |||
| { | |||
| int index = (delta > 0) ? i : (numItems - 1 - i); | |||
| index = (index + numItems) % numItems; | |||
| mic = dynamic_cast <PopupMenu::ItemComponent*> (getChildComponent (index)); | |||
| mic = items.getUnchecked (index); | |||
| if (mic != 0 && (mic->itemInfo.canBeTriggered() || mic->itemInfo.hasActiveSubMenu()) | |||
| && wasLastOne) | |||
| @@ -1713,7 +1696,7 @@ bool PopupMenu::MenuItemIterator::next() | |||
| isSeparator = item->isSeparator; | |||
| isTicked = item->isTicked; | |||
| 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; | |||
| customColour = item->usesColour ? &(item->textColour) : 0; | |||
| customImage = item->image; | |||
| @@ -394,6 +394,7 @@ private: | |||
| friend class PopupMenuCustomComponent; | |||
| friend class MenuBarComponent; | |||
| friend class OwnedArray <Item>; | |||
| friend class OwnedArray <ItemComponent>; | |||
| friend class ScopedPointer <Window>; | |||
| OwnedArray <Item> items; | |||
| @@ -85,7 +85,7 @@ public: | |||
| const Point<int> relativePos (comp->getLocalPoint (0, screenPos)); | |||
| // (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); | |||
| } | |||
| @@ -32,52 +32,29 @@ BEGIN_JUCE_NAMESPACE | |||
| #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 | |||
| { | |||
| public: | |||
| PropertySectionComponent (const String& sectionTitle, | |||
| const Array <PropertyComponent*>& newProperties, | |||
| const bool open) | |||
| const bool sectionIsOpen_) | |||
| : Component (sectionTitle), | |||
| 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() | |||
| { | |||
| deleteAllChildren(); | |||
| propertyComps.clear(); | |||
| } | |||
| void paint (Graphics& g) | |||
| @@ -90,16 +67,11 @@ public: | |||
| { | |||
| 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()) | |||
| { | |||
| 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; | |||
| @@ -123,19 +90,13 @@ public: | |||
| 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); | |||
| if (pp != 0) | |||
| @@ -145,22 +106,13 @@ public: | |||
| bool isOpen() const | |||
| { | |||
| return isOpen_; | |||
| return sectionIsOpen; | |||
| } | |||
| 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) | |||
| @@ -181,45 +133,65 @@ public: | |||
| } | |||
| private: | |||
| OwnedArray <PropertyComponent> propertyComps; | |||
| int titleHeight; | |||
| bool isOpen_; | |||
| bool sectionIsOpen; | |||
| PropertySectionComponent (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() | |||
| @@ -239,7 +211,7 @@ PropertyPanel::~PropertyPanel() | |||
| //============================================================================== | |||
| void PropertyPanel::paint (Graphics& g) | |||
| { | |||
| if (propertyHolderComponent->getNumChildComponents() == 0) | |||
| if (propertyHolderComponent->getNumSections() == 0) | |||
| { | |||
| g.setColour (Colours::black.withAlpha (0.5f)); | |||
| g.setFont (14.0f); | |||
| @@ -257,21 +229,19 @@ void PropertyPanel::resized() | |||
| //============================================================================== | |||
| void PropertyPanel::clear() | |||
| { | |||
| if (propertyHolderComponent->getNumChildComponents() > 0) | |||
| if (propertyHolderComponent->getNumSections() > 0) | |||
| { | |||
| propertyHolderComponent->deleteAllChildren(); | |||
| propertyHolderComponent->clear(); | |||
| repaint(); | |||
| } | |||
| } | |||
| void PropertyPanel::addProperties (const Array <PropertyComponent*>& newProperties) | |||
| { | |||
| if (propertyHolderComponent->getNumChildComponents() == 0) | |||
| if (propertyHolderComponent->getNumSections() == 0) | |||
| repaint(); | |||
| propertyHolderComponent->addAndMakeVisible (new PropertySectionComponent (String::empty, | |||
| newProperties, | |||
| true), 0); | |||
| propertyHolderComponent->addSection (new PropertySectionComponent (String::empty, newProperties, true)); | |||
| updatePropHolderLayout(); | |||
| } | |||
| @@ -281,13 +251,10 @@ void PropertyPanel::addSection (const String& sectionTitle, | |||
| { | |||
| jassert (sectionTitle.isNotEmpty()); | |||
| if (propertyHolderComponent->getNumChildComponents() == 0) | |||
| if (propertyHolderComponent->getNumSections() == 0) | |||
| repaint(); | |||
| propertyHolderComponent->addAndMakeVisible (new PropertySectionComponent (sectionTitle, | |||
| newProperties, | |||
| shouldBeOpen), 0); | |||
| propertyHolderComponent->addSection (new PropertySectionComponent (sectionTitle, newProperties, shouldBeOpen)); | |||
| updatePropHolderLayout(); | |||
| } | |||
| @@ -314,11 +281,11 @@ const StringArray PropertyPanel::getSectionNames() const | |||
| { | |||
| 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()); | |||
| } | |||
| @@ -329,11 +296,11 @@ bool PropertyPanel::isSectionOpen (const int sectionIndex) const | |||
| { | |||
| 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) | |||
| return section->isOpen(); | |||
| @@ -349,11 +316,11 @@ void PropertyPanel::setSectionOpen (const int sectionIndex, const bool shouldBeO | |||
| { | |||
| 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) | |||
| { | |||
| @@ -370,11 +337,11 @@ void PropertyPanel::setSectionEnabled (const int sectionIndex, const bool should | |||
| { | |||
| 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) | |||
| { | |||
| @@ -66,6 +66,7 @@ public: | |||
| of (0, 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 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) | |||
| { | |||
| needToClip = true; | |||
| @@ -49,6 +49,7 @@ public: | |||
| //============================================================================== | |||
| bool isVectorDevice() const; | |||
| void setOrigin (int x, int y); | |||
| void addTransform (const AffineTransform& transform); | |||
| bool clipToRectangle (const Rectangle<int>& r); | |||
| 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() | |||
| { | |||
| 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); | |||
| c[0] += weight * src[0]; | |||
| c[1] += weight * src[1]; | |||
| c[2] += weight * src[2]; | |||
| c[3] += weight * src[3]; | |||
| 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; | |||
| @@ -850,60 +848,56 @@ private: | |||
| c[0] += weight * src[0]; | |||
| c[1] += weight * src[1]; | |||
| c[2] += weight * src[2]; | |||
| c[3] += weight * src[3]; | |||
| 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[1] += weight * src[1]; | |||
| 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, | |||
| (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[1] += weight * src[1]; | |||
| c[2] += weight * src[2]; | |||
| 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, | |||
| (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: | |||
| SavedState (const Rectangle<int>& clip_, const int xOffset_, const int yOffset_) | |||
| : 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_) | |||
| : 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) | |||
| : 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) | |||
| { | |||
| 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; | |||
| @@ -1837,11 +1860,17 @@ public: | |||
| { | |||
| 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; | |||
| @@ -1851,8 +1880,17 @@ public: | |||
| { | |||
| 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; | |||
| @@ -1863,7 +1901,7 @@ public: | |||
| if (clip != 0) | |||
| { | |||
| 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()) | |||
| { | |||
| cloneClipIfMultiplyReferenced(); | |||
| clip = clip->clipToImageAlpha (image, t.translated ((float) xOffset, (float) yOffset), | |||
| clip = clip->clipToImageAlpha (image, getTransformWith (t), | |||
| interpolationQuality != Graphics::lowResamplingQuality); | |||
| } | |||
| else | |||
| @@ -1888,12 +1926,28 @@ public: | |||
| 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 | |||
| { | |||
| 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 (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 | |||
| { | |||
| 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 (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 | |||
| { | |||
| 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) | |||
| { | |||
| 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) | |||
| { | |||
| jassert (isOnlyTranslated); | |||
| if (clip != 0) | |||
| { | |||
| SoftwareRendererClasses::ClipRegion_EdgeTable* edgeTableClip = new SoftwareRendererClasses::ClipRegion_EdgeTable (edgeTable); | |||
| @@ -1970,7 +2044,7 @@ public: | |||
| ColourGradient g2 (*(fillType.gradient)); | |||
| 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(); | |||
| @@ -1998,7 +2072,7 @@ public: | |||
| //============================================================================== | |||
| 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 srcData (sourceImage, false); | |||
| @@ -2055,7 +2129,14 @@ public: | |||
| //============================================================================== | |||
| SoftwareRendererClasses::ClipRegionBase::Ptr clip; | |||
| private: | |||
| AffineTransform complexTransform; | |||
| int xOffset, yOffset; | |||
| public: | |||
| bool isOnlyTranslated; | |||
| Font font; | |||
| FillType fillType; | |||
| Graphics::ResamplingQuality interpolationQuality; | |||
| @@ -2067,6 +2148,22 @@ private: | |||
| 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&); | |||
| }; | |||
| @@ -2100,6 +2197,11 @@ void LowLevelGraphicsSoftwareRenderer::setOrigin (int x, int y) | |||
| currentState->setOrigin (x, y); | |||
| } | |||
| void LowLevelGraphicsSoftwareRenderer::addTransform (const AffineTransform& transform) | |||
| { | |||
| currentState->addTransform (transform); | |||
| } | |||
| bool LowLevelGraphicsSoftwareRenderer::clipToRectangle (const Rectangle<int>& r) | |||
| { | |||
| return currentState->clipToRectangle (r); | |||
| @@ -2353,7 +2455,7 @@ void LowLevelGraphicsSoftwareRenderer::drawGlyph (int glyphNumber, const AffineT | |||
| { | |||
| Font& f = currentState->font; | |||
| if (transform.isOnlyTranslation()) | |||
| if (transform.isOnlyTranslation() && currentState->isOnlyTranslated) | |||
| { | |||
| GlyphCache::getInstance()->drawGlyph (*currentState, image, f, glyphNumber, | |||
| transform.getTranslationX(), | |||
| @@ -49,6 +49,7 @@ public: | |||
| //============================================================================== | |||
| void setOrigin (int x, int y); | |||
| void addTransform (const AffineTransform& transform); | |||
| bool clipToRectangle (const Rectangle<int>& r); | |||
| bool clipToRectangleList (const RectangleList& clipRegion); | |||
| @@ -946,31 +946,19 @@ public: | |||
| 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; | |||
| 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); | |||
| 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) | |||
| @@ -988,7 +976,7 @@ public: | |||
| 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 child == None; | |||
| @@ -180,6 +180,16 @@ public: | |||
| 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) | |||
| { | |||
| CGContextClipToRect (context, CGRectMake (r.getX(), flipHeight - r.getBottom(), r.getWidth(), r.getHeight())); | |||
| @@ -119,6 +119,12 @@ public: | |||
| currentState->origin.addXY (x, y); | |||
| } | |||
| void addTransform (const AffineTransform& transform) | |||
| { | |||
| //xxx todo | |||
| jassertfalse; | |||
| } | |||
| bool clipToRectangle (const Rectangle<int>& r) | |||
| { | |||
| currentState->clipToRectangle (r); | |||