1 /*
2   ==============================================================================
3 
4    This file is part of the JUCE library.
5    Copyright (c) 2020 - Raw Material Software Limited
6 
7    JUCE is an open source library subject to commercial or open-source
8    licensing.
9 
10    By using JUCE, you agree to the terms of both the JUCE 6 End-User License
11    Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
12 
13    End User License Agreement: www.juce.com/juce-6-licence
14    Privacy Policy: www.juce.com/juce-privacy-policy
15 
16    Or: You may also use this code under the terms of the GPL v3 (see
17    www.gnu.org/licenses).
18 
19    JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20    EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
21    DISCLAIMED.
22 
23   ==============================================================================
24 */
25 
26 namespace juce
27 {
28 
ToolbarItemFactory()29 ToolbarItemFactory::ToolbarItemFactory() {}
~ToolbarItemFactory()30 ToolbarItemFactory::~ToolbarItemFactory() {}
31 
32 //==============================================================================
33 class ToolbarItemComponent::ItemDragAndDropOverlayComponent    : public Component
34 {
35 public:
ItemDragAndDropOverlayComponent()36     ItemDragAndDropOverlayComponent()
37         : isDragging (false)
38     {
39         setAlwaysOnTop (true);
40         setRepaintsOnMouseActivity (true);
41         setMouseCursor (MouseCursor::DraggingHandCursor);
42     }
43 
paint(Graphics & g)44     void paint (Graphics& g) override
45     {
46         if (ToolbarItemComponent* const tc = getToolbarItemComponent())
47         {
48             if (isMouseOverOrDragging()
49                   && tc->getEditingMode() == ToolbarItemComponent::editableOnToolbar)
50             {
51                 g.setColour (findColour (Toolbar::editingModeOutlineColourId, true));
52                 g.drawRect (getLocalBounds(), jmin (2, (getWidth() - 1) / 2,
53                                                        (getHeight() - 1) / 2));
54             }
55         }
56     }
57 
mouseDown(const MouseEvent & e)58     void mouseDown (const MouseEvent& e) override
59     {
60         isDragging = false;
61 
62         if (ToolbarItemComponent* const tc = getToolbarItemComponent())
63         {
64             tc->dragOffsetX = e.x;
65             tc->dragOffsetY = e.y;
66         }
67     }
68 
mouseDrag(const MouseEvent & e)69     void mouseDrag (const MouseEvent& e) override
70     {
71         if (e.mouseWasDraggedSinceMouseDown() && ! isDragging)
72         {
73             isDragging = true;
74 
75             if (DragAndDropContainer* const dnd = DragAndDropContainer::findParentDragContainerFor (this))
76             {
77                 dnd->startDragging (Toolbar::toolbarDragDescriptor, getParentComponent(), Image(), true, nullptr, &e.source);
78 
79                 if (ToolbarItemComponent* const tc = getToolbarItemComponent())
80                 {
81                     tc->isBeingDragged = true;
82 
83                     if (tc->getEditingMode() == ToolbarItemComponent::editableOnToolbar)
84                         tc->setVisible (false);
85                 }
86             }
87         }
88     }
89 
mouseUp(const MouseEvent &)90     void mouseUp (const MouseEvent&) override
91     {
92         isDragging = false;
93 
94         if (ToolbarItemComponent* const tc = getToolbarItemComponent())
95         {
96             tc->isBeingDragged = false;
97 
98             if (Toolbar* const tb = tc->getToolbar())
99                 tb->updateAllItemPositions (true);
100             else if (tc->getEditingMode() == ToolbarItemComponent::editableOnToolbar)
101                 delete tc;
102         }
103     }
104 
parentSizeChanged()105     void parentSizeChanged() override
106     {
107         setBounds (0, 0, getParentWidth(), getParentHeight());
108     }
109 
110 private:
111     //==============================================================================
112     bool isDragging;
113 
getToolbarItemComponent() const114     ToolbarItemComponent* getToolbarItemComponent() const noexcept
115     {
116         return dynamic_cast<ToolbarItemComponent*> (getParentComponent());
117     }
118 
119     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ItemDragAndDropOverlayComponent)
120 };
121 
122 
123 //==============================================================================
ToolbarItemComponent(const int itemId_,const String & labelText,const bool isBeingUsedAsAButton_)124 ToolbarItemComponent::ToolbarItemComponent (const int itemId_,
125                                             const String& labelText,
126                                             const bool isBeingUsedAsAButton_)
127     : Button (labelText),
128       itemId (itemId_),
129       mode (normalMode),
130       toolbarStyle (Toolbar::iconsOnly),
131       dragOffsetX (0),
132       dragOffsetY (0),
133       isActive (true),
134       isBeingDragged (false),
135       isBeingUsedAsAButton (isBeingUsedAsAButton_)
136 {
137     // Your item ID can't be 0!
138     jassert (itemId_ != 0);
139 }
140 
~ToolbarItemComponent()141 ToolbarItemComponent::~ToolbarItemComponent()
142 {
143     overlayComp.reset();
144 }
145 
getToolbar() const146 Toolbar* ToolbarItemComponent::getToolbar() const
147 {
148     return dynamic_cast<Toolbar*> (getParentComponent());
149 }
150 
isToolbarVertical() const151 bool ToolbarItemComponent::isToolbarVertical() const
152 {
153     const Toolbar* const t = getToolbar();
154     return t != nullptr && t->isVertical();
155 }
156 
setStyle(const Toolbar::ToolbarItemStyle & newStyle)157 void ToolbarItemComponent::setStyle (const Toolbar::ToolbarItemStyle& newStyle)
158 {
159     if (toolbarStyle != newStyle)
160     {
161         toolbarStyle = newStyle;
162         repaint();
163         resized();
164     }
165 }
166 
paintButton(Graphics & g,const bool over,const bool down)167 void ToolbarItemComponent::paintButton (Graphics& g, const bool over, const bool down)
168 {
169     if (isBeingUsedAsAButton)
170         getLookAndFeel().paintToolbarButtonBackground (g, getWidth(), getHeight(),
171                                                        over, down, *this);
172 
173     if (toolbarStyle != Toolbar::iconsOnly)
174     {
175         auto indent = contentArea.getX();
176         auto y = indent;
177         auto h = getHeight() - indent * 2;
178 
179         if (toolbarStyle == Toolbar::iconsWithText)
180         {
181             y = contentArea.getBottom() + indent / 2;
182             h -= contentArea.getHeight();
183         }
184 
185         getLookAndFeel().paintToolbarButtonLabel (g, indent, y, getWidth() - indent * 2, h,
186                                                   getButtonText(), *this);
187     }
188 
189     if (! contentArea.isEmpty())
190     {
191         Graphics::ScopedSaveState ss (g);
192 
193         g.reduceClipRegion (contentArea);
194         g.setOrigin (contentArea.getPosition());
195 
196         paintButtonArea (g, contentArea.getWidth(), contentArea.getHeight(), over, down);
197     }
198 }
199 
resized()200 void ToolbarItemComponent::resized()
201 {
202     if (toolbarStyle != Toolbar::textOnly)
203     {
204         const int indent = jmin (proportionOfWidth (0.08f),
205                                  proportionOfHeight (0.08f));
206 
207         contentArea = Rectangle<int> (indent, indent,
208                                       getWidth() - indent * 2,
209                                       toolbarStyle == Toolbar::iconsWithText ? proportionOfHeight (0.55f)
210                                                                              : (getHeight() - indent * 2));
211     }
212     else
213     {
214         contentArea = {};
215     }
216 
217     contentAreaChanged (contentArea);
218 }
219 
setEditingMode(const ToolbarEditingMode newMode)220 void ToolbarItemComponent::setEditingMode (const ToolbarEditingMode newMode)
221 {
222     if (mode != newMode)
223     {
224         mode = newMode;
225         repaint();
226 
227         if (mode == normalMode)
228         {
229             overlayComp.reset();
230         }
231         else if (overlayComp == nullptr)
232         {
233             overlayComp.reset (new ItemDragAndDropOverlayComponent());
234             addAndMakeVisible (overlayComp.get());
235             overlayComp->parentSizeChanged();
236         }
237 
238         resized();
239     }
240 }
241 
242 } // namespace juce
243