@@ -431,7 +431,7 @@ void ProjectTreeViewBase::addSubItems() | |||
void ProjectTreeViewBase::refreshSubItems() | |||
{ | |||
OpennessRestorer openness (*this); | |||
WholeTreeOpennessRestorer openness (*this); | |||
clearSubItems(); | |||
addSubItems(); | |||
} | |||
@@ -39,7 +39,7 @@ public: | |||
bool acceptsFileDrop (const StringArray& files) const { return false; } | |||
bool acceptsDragItems (const OwnedArray <Project::Item>& selectedNodes) { return false; } | |||
ProjectTreeViewBase* createSubItem (const Project::Item& child); | |||
void createLeftEdgeComponents (Array<Component*>& components) {} | |||
void createLeftEdgeComponents (OwnedArray<Component>& components) {} | |||
void showDocument(); | |||
void showPopupMenu(); | |||
String getDisplayName() const; | |||
@@ -59,7 +59,7 @@ public: | |||
void checkFileStatus(); | |||
void moveSelectedItemsTo (OwnedArray <Project::Item>& selectedNodes, int insertIndex); | |||
ProjectTreeViewBase* createSubItem (const Project::Item& child); | |||
void createLeftEdgeComponents (Array<Component*>& components) {} | |||
void createLeftEdgeComponents (OwnedArray<Component>& components) {} | |||
void showDocument(); | |||
void showPopupMenu(); | |||
@@ -69,9 +69,9 @@ void JucerTreeViewBase::paintOpenCloseButton (Graphics& g, int width, int height | |||
Path p; | |||
if (isOpen()) | |||
p.addTriangle (width * 0.2f, height * 0.25f, width * 0.8f, height * 0.25f, width * 0.5f, height * 0.75f); | |||
p.addTriangle (width * 0.2f, height * 0.25f, width * 0.8f, height * 0.25f, width * 0.5f, height * 0.75f); | |||
else | |||
p.addTriangle (width * 0.25f, height * 0.25f, width * 0.8f, height * 0.5f, width * 0.25f, height * 0.75f); | |||
p.addTriangle (width * 0.25f, height * 0.25f, width * 0.8f, height * 0.5f, width * 0.25f, height * 0.75f); | |||
g.setColour (Colours::lightgrey); | |||
g.fillPath (p); | |||
@@ -81,13 +81,13 @@ void JucerTreeViewBase::paintOpenCloseButton (Graphics& g, int width, int height | |||
class TreeLeftHandButtonHolderComponent : public Component | |||
{ | |||
public: | |||
TreeLeftHandButtonHolderComponent (const Array<Component*>& comps) | |||
TreeLeftHandButtonHolderComponent (OwnedArray<Component>& comps) | |||
{ | |||
components.addArray (comps); | |||
components.swapWithArray (comps); | |||
setInterceptsMouseClicks (false, true); | |||
for (int i = 0; i < comps.size(); ++i) | |||
addAndMakeVisible (comps.getUnchecked(i)); | |||
for (int i = 0; i < components.size(); ++i) | |||
addAndMakeVisible (components.getUnchecked(i)); | |||
} | |||
void resized() | |||
@@ -105,7 +105,7 @@ private: | |||
Component* JucerTreeViewBase::createItemComponent() | |||
{ | |||
Array<Component*> components; | |||
OwnedArray<Component> components; | |||
createLeftEdgeComponents (components); | |||
numLeftHandComps = components.size(); | |||
@@ -113,24 +113,44 @@ Component* JucerTreeViewBase::createItemComponent() | |||
} | |||
//============================================================================== | |||
void JucerTreeViewBase::showRenameBox() | |||
class RenameTreeItemCallback : public ModalComponentManager::Callback | |||
{ | |||
TextEditor ed (String::empty); | |||
ed.setMultiLine (false, false); | |||
ed.setPopupMenuEnabled (false); | |||
ed.setSelectAllWhenFocused (true); | |||
ed.setFont (getFont()); | |||
ed.addListener (this); | |||
ed.setText (getRenamingName()); | |||
public: | |||
RenameTreeItemCallback (JucerTreeViewBase& item_, Component& parent, const Rectangle<int>& bounds) | |||
: item (item_) | |||
{ | |||
ed.setMultiLine (false, false); | |||
ed.setPopupMenuEnabled (false); | |||
ed.setSelectAllWhenFocused (true); | |||
ed.setFont (item.getFont()); | |||
ed.addListener (&item); | |||
ed.setText (item.getRenamingName()); | |||
ed.setBounds (bounds); | |||
parent.addAndMakeVisible (&ed); | |||
ed.enterModalState (true, this); | |||
} | |||
void modalStateFinished (int resultCode) | |||
{ | |||
if (resultCode != 0) | |||
item.setName (ed.getText()); | |||
} | |||
private: | |||
TextEditor ed; | |||
JucerTreeViewBase& item; | |||
JUCE_DECLARE_NON_COPYABLE (RenameTreeItemCallback); | |||
}; | |||
void JucerTreeViewBase::showRenameBox() | |||
{ | |||
Rectangle<int> r (getItemPosition (true)); | |||
r.setLeft (r.getX() + getTextX()); | |||
r.setHeight (getItemHeight()); | |||
ed.setBounds (r); | |||
getOwnerView()->addAndMakeVisible (&ed); | |||
if (ed.runModalLoop() != 0) | |||
setName (ed.getText()); | |||
new RenameTreeItemCallback (*this, *getOwnerView(), r); | |||
} | |||
void JucerTreeViewBase::itemClicked (const MouseEvent& e) | |||
@@ -42,6 +42,7 @@ public: | |||
//============================================================================== | |||
int getItemWidth() const { return -1; } | |||
int getItemHeight() const { return 20; } | |||
Font getFont() const; | |||
void paintItem (Graphics& g, int width, int height); | |||
void paintOpenCloseButton (Graphics& g, int width, int height, bool isMouseOver); | |||
@@ -54,7 +55,7 @@ public: | |||
virtual void setName (const String& newName) = 0; | |||
virtual bool isMissing() = 0; | |||
virtual const Drawable* getIcon() const = 0; | |||
virtual void createLeftEdgeComponents (Array<Component*>& components) = 0; | |||
virtual void createLeftEdgeComponents (OwnedArray<Component>& components) = 0; | |||
virtual void showPopupMenu(); | |||
virtual void showMultiSelectionPopupMenu(); | |||
@@ -67,10 +68,26 @@ public: | |||
void textEditorEscapeKeyPressed (TextEditor& editor) { editor.exitModalState (0); } | |||
void textEditorFocusLost (TextEditor& editor) { editor.exitModalState (0); } | |||
//============================================================================== | |||
// To handle situations where an item gets deleted before openness is | |||
// restored for it, this OpennessRestorer keeps only a pointer to the | |||
// topmost tree item. | |||
struct WholeTreeOpennessRestorer : public OpennessRestorer | |||
{ | |||
WholeTreeOpennessRestorer (TreeViewItem& item) : OpennessRestorer (getTopLevelItem (item)) | |||
{} | |||
private: | |||
static TreeViewItem& getTopLevelItem (TreeViewItem& item) | |||
{ | |||
TreeViewItem* const p = item.getParentItem(); | |||
return p != nullptr ? getTopLevelItem (*p) : item; | |||
} | |||
}; | |||
//============================================================================== | |||
private: | |||
int numLeftHandComps; | |||
Font getFont() const; | |||
int getTextX() const; | |||
}; | |||
@@ -405,3 +405,29 @@ void showUTF8ToolWindow() | |||
DialogWindow::showModalDialog ("UTF-8 String Literal Converter", &comp, | |||
nullptr, Colours::white, true, true); | |||
} | |||
//============================================================================== | |||
class CallOutBoxCallback : public ModalComponentManager::Callback | |||
{ | |||
public: | |||
CallOutBoxCallback (Component& attachTo, Component* content_) | |||
: content (content_), | |||
callout (*content_, attachTo, attachTo.getTopLevelComponent()) | |||
{ | |||
callout.setVisible (true); | |||
callout.enterModalState (true, this); | |||
} | |||
void modalStateFinished (int) {} | |||
private: | |||
ScopedPointer<Component> content; | |||
CallOutBox callout; | |||
JUCE_DECLARE_NON_COPYABLE (CallOutBoxCallback); | |||
}; | |||
void launchAsyncCallOutBox (Component& attachTo, Component* content) | |||
{ | |||
new CallOutBoxCallback (attachTo, content); | |||
} |
@@ -46,6 +46,9 @@ void drawRecessedShadows (Graphics& g, int w, int h, int shadowSize); | |||
void showUTF8ToolWindow(); | |||
// Start a callout modally, which will delete the content comp when it's dismissed. | |||
void launchAsyncCallOutBox (Component& attachTo, Component* content); | |||
//============================================================================== | |||
class PropertyPanelWithTooltips : public Component, | |||
public Timer | |||
@@ -434,7 +434,7 @@ void Graphics::drawBevel (const int x, const int y, const int width, const int h | |||
for (int i = bevelThickness; --i >= 0;) | |||
{ | |||
const float op = useGradient ? (sharpEdgeOnOutside ? bevelThickness - i : i) / bevelThickness | |||
const float op = useGradient ? (sharpEdgeOnOutside ? bevelThickness - i : i) / (float) bevelThickness | |||
: 1.0f; | |||
context->setFill (topLeftColour.withMultipliedAlpha (op)); | |||
@@ -607,13 +607,13 @@ void Graphics::drawDashedLine (const Line<float>& line, const float* const dashL | |||
jassert (dashLengths[n] > 0); // can't have zero-length dashes! | |||
const double lastAlpha = alpha; | |||
alpha = jmin (1.0, alpha + dashLengths [n] * onePixAlpha); | |||
alpha += dashLengths [n] * onePixAlpha; | |||
n = (n + 1) % numDashLengths; | |||
if ((n & 1) != 0) | |||
{ | |||
const Line<float> segment (line.getStart() + (delta * lastAlpha).toFloat(), | |||
line.getStart() + (delta * alpha).toFloat()); | |||
line.getStart() + (delta * jmin (1.0, alpha)).toFloat()); | |||
if (lineThickness != 1.0f) | |||
drawLine (segment, lineThickness); | |||