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