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