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 #include "../../Application/jucer_Headers.h"
27 #include "../../Application/jucer_Application.h"
28 #include "../UI/jucer_JucerCommandIDs.h"
29 #include "jucer_PaintRoutineEditor.h"
30 #include "../jucer_ObjectTypes.h"
31 #include "jucer_JucerDocumentEditor.h"
32 
33 //==============================================================================
PaintRoutineEditor(PaintRoutine & pr,JucerDocument & doc,JucerDocumentEditor * docHolder)34 PaintRoutineEditor::PaintRoutineEditor (PaintRoutine& pr, JucerDocument& doc,
35                                         JucerDocumentEditor* docHolder)
36     : graphics (pr),
37       document (doc),
38       documentHolder (docHolder),
39       componentOverlay (nullptr),
40       componentOverlayOpacity (0.0f)
41 {
42     refreshAllElements();
43 
44     setSize (document.getInitialWidth(),
45              document.getInitialHeight());
46 }
47 
~PaintRoutineEditor()48 PaintRoutineEditor::~PaintRoutineEditor()
49 {
50     document.removeChangeListener (this);
51     removeAllElementComps();
52     removeChildComponent (&lassoComp);
53     deleteAllChildren();
54 }
55 
removeAllElementComps()56 void PaintRoutineEditor::removeAllElementComps()
57 {
58     for (int i = getNumChildComponents(); --i >= 0;)
59         if (PaintElement* const e = dynamic_cast<PaintElement*> (getChildComponent (i)))
60             removeChildComponent (e);
61 }
62 
getComponentArea() const63 Rectangle<int> PaintRoutineEditor::getComponentArea() const
64 {
65     if (document.isFixedSize())
66         return Rectangle<int> ((getWidth() - document.getInitialWidth()) / 2,
67                                (getHeight() - document.getInitialHeight()) / 2,
68                                document.getInitialWidth(),
69                                document.getInitialHeight());
70 
71     return getLocalBounds().reduced (4);
72 }
73 
74 //==============================================================================
paint(Graphics & g)75 void PaintRoutineEditor::paint (Graphics& g)
76 {
77     const Rectangle<int> clip (getComponentArea());
78 
79     g.reduceClipRegion (clip);
80     g.setOrigin (clip.getPosition());
81 
82     graphics.fillWithBackground (g, true);
83     grid.draw (g, &graphics);
84 }
85 
paintOverChildren(Graphics & g)86 void PaintRoutineEditor::paintOverChildren (Graphics& g)
87 {
88     if (componentOverlay.isNull() && document.getComponentOverlayOpacity() > 0.0f)
89         updateComponentOverlay();
90 
91     if (componentOverlay.isValid())
92     {
93         const Rectangle<int> clip (getComponentArea());
94         g.drawImageAt (componentOverlay, clip.getX(), clip.getY());
95     }
96 }
97 
resized()98 void PaintRoutineEditor::resized()
99 {
100     if (getWidth() > 0 && getHeight() > 0)
101     {
102         componentOverlay = Image();
103         refreshAllElements();
104     }
105 }
106 
updateChildBounds()107 void PaintRoutineEditor::updateChildBounds()
108 {
109     const Rectangle<int> clip (getComponentArea());
110 
111     for (int i = 0; i < getNumChildComponents(); ++i)
112         if (PaintElement* const e = dynamic_cast<PaintElement*> (getChildComponent (i)))
113             e->updateBounds (clip);
114 }
115 
updateComponentOverlay()116 void PaintRoutineEditor::updateComponentOverlay()
117 {
118     if (componentOverlay.isValid())
119         repaint();
120 
121     componentOverlay = Image();
122     componentOverlayOpacity = document.getComponentOverlayOpacity();
123 
124     if (componentOverlayOpacity > 0.0f)
125     {
126         if (documentHolder != nullptr)
127             componentOverlay = documentHolder->createComponentLayerSnapshot();
128 
129         if (componentOverlay.isValid())
130         {
131             componentOverlay.multiplyAllAlphas (componentOverlayOpacity);
132             repaint();
133         }
134     }
135 }
136 
visibilityChanged()137 void PaintRoutineEditor::visibilityChanged()
138 {
139     document.beginTransaction();
140 
141     if (isVisible())
142     {
143         refreshAllElements();
144         document.addChangeListener (this);
145     }
146     else
147     {
148         document.removeChangeListener (this);
149         componentOverlay = Image();
150     }
151 }
152 
refreshAllElements()153 void PaintRoutineEditor::refreshAllElements()
154 {
155     for (int i = getNumChildComponents(); --i >= 0;)
156         if (auto* e = dynamic_cast<PaintElement*> (getChildComponent (i)))
157             if (! graphics.containsElement (e))
158                 removeChildComponent (e);
159 
160     Component* last = nullptr;
161 
162     for (int i = graphics.getNumElements(); --i >= 0;)
163     {
164         auto* e = graphics.getElement (i);
165 
166         addAndMakeVisible (e);
167 
168         if (last != nullptr)
169             e->toBehind (last);
170         else
171             e->toFront (false);
172 
173         last = e;
174     }
175 
176     updateChildBounds();
177 
178     if (grid.updateFromDesign (document))
179         repaint();
180 
181     if (currentBackgroundColour != graphics.getBackgroundColour())
182     {
183         currentBackgroundColour = graphics.getBackgroundColour();
184         repaint();
185     }
186 
187     if (componentOverlayOpacity != document.getComponentOverlayOpacity())
188     {
189         componentOverlay = Image();
190         componentOverlayOpacity = document.getComponentOverlayOpacity();
191         repaint();
192     }
193 }
194 
changeListenerCallback(ChangeBroadcaster *)195 void PaintRoutineEditor::changeListenerCallback (ChangeBroadcaster*)
196 {
197     refreshAllElements();
198 }
199 
mouseDown(const MouseEvent & e)200 void PaintRoutineEditor::mouseDown (const MouseEvent& e)
201 {
202     if (e.mods.isPopupMenu())
203     {
204         ApplicationCommandManager* commandManager = &ProjucerApplication::getCommandManager();
205 
206         PopupMenu m;
207 
208         m.addCommandItem (commandManager, JucerCommandIDs::editCompLayout);
209         m.addCommandItem (commandManager, JucerCommandIDs::editCompGraphics);
210         m.addSeparator();
211 
212         for (int i = 0; i < ObjectTypes::numElementTypes; ++i)
213             m.addCommandItem (commandManager, JucerCommandIDs::newElementBase + i);
214 
215         m.show();
216     }
217     else
218     {
219         addChildComponent (lassoComp);
220         lassoComp.beginLasso (e, this);
221     }
222 }
223 
mouseDrag(const MouseEvent & e)224 void PaintRoutineEditor::mouseDrag (const MouseEvent& e)
225 {
226     lassoComp.toFront (false);
227     lassoComp.dragLasso (e);
228 }
229 
mouseUp(const MouseEvent & e)230 void PaintRoutineEditor::mouseUp (const MouseEvent& e)
231 {
232     lassoComp.endLasso();
233 
234     if (! (e.mouseWasDraggedSinceMouseDown() || e.mods.isAnyModifierKeyDown()))
235     {
236         graphics.getSelectedElements().deselectAll();
237         graphics.getSelectedPoints().deselectAll();
238     }
239 }
240 
findLassoItemsInArea(Array<PaintElement * > & results,const Rectangle<int> & lasso)241 void PaintRoutineEditor::findLassoItemsInArea (Array <PaintElement*>& results, const Rectangle<int>& lasso)
242 {
243     for (int i = 0; i < getNumChildComponents(); ++i)
244         if (PaintElement* const e = dynamic_cast<PaintElement*> (getChildComponent (i)))
245             if (e->getBounds().expanded (-e->borderThickness).intersects (lasso))
246                 results.add (e);
247 }
248 
getLassoSelection()249 SelectedItemSet <PaintElement*>& PaintRoutineEditor::getLassoSelection()
250 {
251     return graphics.getSelectedElements();
252 }
253 
isInterestedInFileDrag(const StringArray & files)254 bool PaintRoutineEditor::isInterestedInFileDrag (const StringArray& files)
255 {
256     return File::createFileWithoutCheckingPath (files[0])
257              .hasFileExtension ("jpg;jpeg;png;gif;svg");
258 }
259 
filesDropped(const StringArray & filenames,int x,int y)260 void PaintRoutineEditor::filesDropped (const StringArray& filenames, int x, int y)
261 {
262     const File f (filenames [0]);
263 
264     if (f.existsAsFile())
265     {
266         std::unique_ptr<Drawable> d (Drawable::createFromImageFile (f));
267 
268         if (d != nullptr)
269         {
270             d.reset();
271 
272             document.beginTransaction();
273 
274             graphics.dropImageAt (f,
275                                   jlimit (10, getWidth() - 10, x),
276                                   jlimit (10, getHeight() - 10, y));
277 
278             document.beginTransaction();
279         }
280     }
281 }
282