|
- /*
- ==============================================================================
-
- This file is part of the JUCE library - "Jules' Utility Class Extensions"
- Copyright 2004-11 by Raw Material Software Ltd.
-
- ------------------------------------------------------------------------------
-
- JUCE can be redistributed and/or modified under the terms of the GNU General
- Public License (Version 2), as published by the Free Software Foundation.
- A copy of the license is included in the JUCE distribution, or can be found
- online at www.gnu.org/licenses.
-
- JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- ------------------------------------------------------------------------------
-
- To release a closed-source product which uses JUCE, commercial licenses are
- available: visit www.rawmaterialsoftware.com/juce for more information.
-
- ==============================================================================
- */
-
- class PropertyPanel::SectionComponent : public Component
- {
- public:
- SectionComponent (const String& sectionTitle,
- const Array <PropertyComponent*>& newProperties,
- const bool sectionIsOpen_)
- : Component (sectionTitle),
- titleHeight (sectionTitle.isNotEmpty() ? 22 : 0),
- sectionIsOpen (sectionIsOpen_)
- {
- propertyComps.addArray (newProperties);
-
- for (int i = propertyComps.size(); --i >= 0;)
- {
- addAndMakeVisible (propertyComps.getUnchecked(i));
- propertyComps.getUnchecked(i)->refresh();
- }
- }
-
- ~SectionComponent()
- {
- propertyComps.clear();
- }
-
- void paint (Graphics& g)
- {
- if (titleHeight > 0)
- getLookAndFeel().drawPropertyPanelSectionHeader (g, getName(), isOpen(), getWidth(), titleHeight);
- }
-
- void resized()
- {
- int y = titleHeight;
-
- for (int i = 0; i < propertyComps.size(); ++i)
- {
- PropertyComponent* const pec = propertyComps.getUnchecked (i);
- pec->setBounds (1, y, getWidth() - 2, pec->getPreferredHeight());
- y = pec->getBottom();
- }
- }
-
- int getPreferredHeight() const
- {
- int y = titleHeight;
-
- if (isOpen())
- {
- for (int i = propertyComps.size(); --i >= 0;)
- y += propertyComps.getUnchecked(i)->getPreferredHeight();
- }
-
- return y;
- }
-
- void setOpen (const bool open)
- {
- if (sectionIsOpen != open)
- {
- sectionIsOpen = open;
-
- for (int i = propertyComps.size(); --i >= 0;)
- propertyComps.getUnchecked(i)->setVisible (open);
-
- PropertyPanel* const pp = findParentComponentOfClass<PropertyPanel>();
-
- if (pp != nullptr)
- pp->resized();
- }
- }
-
- bool isOpen() const
- {
- return sectionIsOpen;
- }
-
- void refreshAll() const
- {
- for (int i = propertyComps.size(); --i >= 0;)
- propertyComps.getUnchecked (i)->refresh();
- }
-
- void mouseUp (const MouseEvent& e)
- {
- if (e.getMouseDownX() < titleHeight
- && e.x < titleHeight
- && e.y < titleHeight
- && e.getNumberOfClicks() != 2)
- {
- setOpen (! isOpen());
- }
- }
-
- void mouseDoubleClick (const MouseEvent& e)
- {
- if (e.y < titleHeight)
- setOpen (! isOpen());
- }
-
- private:
- OwnedArray <PropertyComponent> propertyComps;
- int titleHeight;
- bool sectionIsOpen;
-
- JUCE_DECLARE_NON_COPYABLE (SectionComponent);
- };
-
- //==============================================================================
- class PropertyPanel::PropertyHolderComponent : public Component
- {
- public:
- PropertyHolderComponent() {}
-
- void paint (Graphics&) {}
-
- void updateLayout (int width)
- {
- int y = 0;
-
- for (int i = 0; i < sections.size(); ++i)
- {
- SectionComponent* const section = sections.getUnchecked(i);
-
- section->setBounds (0, y, width, section->getPreferredHeight());
- y = section->getBottom();
- }
-
- setSize (width, y);
- repaint();
- }
-
- void refreshAll() const
- {
- for (int i = 0; i < sections.size(); ++i)
- sections.getUnchecked(i)->refreshAll();
- }
-
- void clear()
- {
- sections.clear();
- }
-
- void addSection (SectionComponent* newSection)
- {
- sections.add (newSection);
- addAndMakeVisible (newSection, 0);
- }
-
- int getNumSections() const noexcept { return sections.size(); }
- SectionComponent* getSection (const int index) const { return sections [index]; }
-
- private:
- OwnedArray<SectionComponent> sections;
-
- JUCE_DECLARE_NON_COPYABLE (PropertyHolderComponent);
- };
-
-
- //==============================================================================
- PropertyPanel::PropertyPanel()
- {
- messageWhenEmpty = TRANS("(nothing selected)");
-
- addAndMakeVisible (&viewport);
- viewport.setViewedComponent (propertyHolderComponent = new PropertyHolderComponent());
- viewport.setFocusContainer (true);
- }
-
- PropertyPanel::~PropertyPanel()
- {
- clear();
- }
-
- //==============================================================================
- void PropertyPanel::paint (Graphics& g)
- {
- if (propertyHolderComponent->getNumSections() == 0)
- {
- g.setColour (Colours::black.withAlpha (0.5f));
- g.setFont (14.0f);
- g.drawText (messageWhenEmpty, getLocalBounds().withHeight (30),
- Justification::centred, true);
- }
- }
-
- void PropertyPanel::resized()
- {
- viewport.setBounds (getLocalBounds());
- updatePropHolderLayout();
- }
-
- //==============================================================================
- void PropertyPanel::clear()
- {
- if (propertyHolderComponent->getNumSections() > 0)
- {
- propertyHolderComponent->clear();
- repaint();
- }
- }
-
- void PropertyPanel::addProperties (const Array <PropertyComponent*>& newProperties)
- {
- if (propertyHolderComponent->getNumSections() == 0)
- repaint();
-
- propertyHolderComponent->addSection (new SectionComponent (String::empty, newProperties, true));
- updatePropHolderLayout();
- }
-
- void PropertyPanel::addSection (const String& sectionTitle,
- const Array <PropertyComponent*>& newProperties,
- const bool shouldBeOpen)
- {
- jassert (sectionTitle.isNotEmpty());
-
- if (propertyHolderComponent->getNumSections() == 0)
- repaint();
-
- propertyHolderComponent->addSection (new SectionComponent (sectionTitle, newProperties, shouldBeOpen));
- updatePropHolderLayout();
- }
-
- void PropertyPanel::updatePropHolderLayout() const
- {
- const int maxWidth = viewport.getMaximumVisibleWidth();
- propertyHolderComponent->updateLayout (maxWidth);
-
- const int newMaxWidth = viewport.getMaximumVisibleWidth();
- if (maxWidth != newMaxWidth)
- {
- // need to do this twice because of scrollbars changing the size, etc.
- propertyHolderComponent->updateLayout (newMaxWidth);
- }
- }
-
- void PropertyPanel::refreshAll() const
- {
- propertyHolderComponent->refreshAll();
- }
-
- //==============================================================================
- StringArray PropertyPanel::getSectionNames() const
- {
- StringArray s;
-
- for (int i = 0; i < propertyHolderComponent->getNumSections(); ++i)
- {
- SectionComponent* const section = propertyHolderComponent->getSection (i);
-
- if (section->getName().isNotEmpty())
- s.add (section->getName());
- }
-
- return s;
- }
-
- bool PropertyPanel::isSectionOpen (const int sectionIndex) const
- {
- int index = 0;
-
- for (int i = 0; i < propertyHolderComponent->getNumSections(); ++i)
- {
- SectionComponent* const section = propertyHolderComponent->getSection (i);
-
- if (section->getName().isNotEmpty())
- {
- if (index == sectionIndex)
- return section->isOpen();
-
- ++index;
- }
- }
-
- return false;
- }
-
- void PropertyPanel::setSectionOpen (const int sectionIndex, const bool shouldBeOpen)
- {
- int index = 0;
-
- for (int i = 0; i < propertyHolderComponent->getNumSections(); ++i)
- {
- SectionComponent* const section = propertyHolderComponent->getSection (i);
-
- if (section->getName().isNotEmpty())
- {
- if (index == sectionIndex)
- {
- section->setOpen (shouldBeOpen);
- break;
- }
-
- ++index;
- }
- }
- }
-
- void PropertyPanel::setSectionEnabled (const int sectionIndex, const bool shouldBeEnabled)
- {
- int index = 0;
-
- for (int i = 0; i < propertyHolderComponent->getNumSections(); ++i)
- {
- SectionComponent* const section = propertyHolderComponent->getSection (i);
-
- if (section->getName().isNotEmpty())
- {
- if (index == sectionIndex)
- {
- section->setEnabled (shouldBeEnabled);
- break;
- }
-
- ++index;
- }
- }
- }
-
- //==============================================================================
- XmlElement* PropertyPanel::getOpennessState() const
- {
- XmlElement* const xml = new XmlElement ("PROPERTYPANELSTATE");
-
- xml->setAttribute ("scrollPos", viewport.getViewPositionY());
-
- const StringArray sections (getSectionNames());
-
- for (int i = 0; i < sections.size(); ++i)
- {
- if (sections[i].isNotEmpty())
- {
- XmlElement* const e = xml->createNewChildElement ("SECTION");
- e->setAttribute ("name", sections[i]);
- e->setAttribute ("open", isSectionOpen (i) ? 1 : 0);
- }
- }
-
- return xml;
- }
-
- void PropertyPanel::restoreOpennessState (const XmlElement& xml)
- {
- if (xml.hasTagName ("PROPERTYPANELSTATE"))
- {
- const StringArray sections (getSectionNames());
-
- forEachXmlChildElementWithTagName (xml, e, "SECTION")
- {
- setSectionOpen (sections.indexOf (e->getStringAttribute ("name")),
- e->getBoolAttribute ("open"));
- }
-
- viewport.setViewPosition (viewport.getViewPositionX(),
- xml.getIntAttribute ("scrollPos", viewport.getViewPositionY()));
- }
- }
-
- //==============================================================================
- void PropertyPanel::setMessageWhenEmpty (const String& newMessage)
- {
- if (messageWhenEmpty != newMessage)
- {
- messageWhenEmpty = newMessage;
- repaint();
- }
- }
-
- const String& PropertyPanel::getMessageWhenEmpty() const
- {
- return messageWhenEmpty;
- }
|