LMMS
Loading...
Searching...
No Matches
juce_MultiDocumentPanel.cpp
Go to the documentation of this file.
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - 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 7 End-User License
11 Agreement and JUCE Privacy Policy.
12
13 End User License Agreement: www.juce.com/juce-7-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
26namespace juce
27{
28
34
38
39//==============================================================================
41{
42 if (auto* owner = getOwner())
44 else
45 jassertfalse; // these windows are only designed to be used inside a MultiDocumentPanel!
46}
47
49{
50 if (auto* owner = getOwner())
51 owner->closeDocumentAsync (getContentComponent(), true, nullptr);
52 else
53 jassertfalse; // these windows are only designed to be used inside a MultiDocumentPanel!
54}
55
61
67
69{
70 if (auto* owner = getOwner())
71 owner->updateOrder();
72}
73
78
79//==============================================================================
81{
83
84 void currentTabChanged (int, const String&) override
85 {
87 owner->updateOrder();
88 }
89};
90
91
92//==============================================================================
97
99{
100 for (int i = components.size(); --i >= 0;)
101 if (auto* component = components[i])
102 closeDocumentInternal (component);
103}
104
105//==============================================================================
107{
108 static bool shouldDeleteComp (Component* const c)
109 {
110 return c->getProperties() ["mdiDocumentDelete_"];
111 }
112}
113
114#if JUCE_MODAL_LOOPS_PERMITTED
115bool MultiDocumentPanel::closeAllDocuments (const bool checkItsOkToCloseFirst)
116{
117 while (! components.isEmpty())
118 if (! closeDocument (components.getLast(), checkItsOkToCloseFirst))
119 return false;
120
121 return true;
122}
123#endif
124
126 bool checkItsOkToCloseFirst,
127 std::function<void (bool)> callback)
128{
129 if (parent->components.isEmpty())
130 {
131 if (callback != nullptr)
132 callback (true);
133
134 return;
135 }
136
137 parent->closeDocumentAsync (parent->components.getLast(),
138 checkItsOkToCloseFirst,
139 [parent, checkItsOkToCloseFirst, callback] (bool closeResult)
140 {
141 if (parent == nullptr)
142 return;
143
144 if (! closeResult)
145 {
146 if (callback != nullptr)
147 callback (false);
148
149 return;
150 }
151
152 parent->closeLastDocumentRecursive (parent, checkItsOkToCloseFirst, std::move (callback));
153 });
154}
155
156void MultiDocumentPanel::closeAllDocumentsAsync (bool checkItsOkToCloseFirst, std::function<void (bool)> callback)
157{
158 closeLastDocumentRecursive (this, checkItsOkToCloseFirst, std::move (callback));
159}
160
161#if JUCE_MODAL_LOOPS_PERMITTED
162bool MultiDocumentPanel::tryToCloseDocument (Component*)
163{
164 // If you hit this assertion then you need to implement this method in a subclass.
166 return false;
167}
168#endif
169
174
176{
177 auto* dw = createNewDocumentWindow();
178
179 dw->setResizable (true, false);
180 dw->setContentNonOwned (component, true);
181 dw->setName (component->getName());
182
183 auto bkg = component->getProperties() ["mdiDocumentBkg_"];
184 dw->setBackgroundColour (bkg.isVoid() ? backgroundColour : Colour ((uint32) static_cast<int> (bkg)));
185
186 int x = 4;
187
188 if (auto* topComp = getChildren().getLast())
189 if (topComp->getX() == x && topComp->getY() == x)
190 x += 16;
191
192 dw->setTopLeftPosition (x, x);
193
194 auto pos = component->getProperties() ["mdiDocumentPos_"];
195 if (pos.toString().isNotEmpty())
196 dw->restoreWindowStateFromString (pos.toString());
197
199 dw->toFront (true);
200}
201
203 Colour docColour,
204 const bool deleteWhenRemoved)
205{
206 // If you try passing a full DocumentWindow or ResizableWindow in here, you'll end up
207 // with a frame-within-a-frame! Just pass in the bare content component.
208 jassert (dynamic_cast<ResizableWindow*> (component) == nullptr);
209
210 if (component == nullptr || (maximumNumDocuments > 0 && components.size() >= maximumNumDocuments))
211 return false;
212
213 components.add (component);
214 component->getProperties().set ("mdiDocumentDelete_", deleteWhenRemoved);
215 component->getProperties().set ("mdiDocumentBkg_", (int) docColour.getARGB());
216 component->addComponentListener (this);
217
218 if (mode == FloatingWindows)
219 {
221 {
222 if (components.size() == 1)
223 {
224 addAndMakeVisible (component);
225 }
226 else
227 {
228 if (components.size() == 2)
229 addWindow (components.getFirst());
230
231 addWindow (component);
232 }
233 }
234 else
235 {
236 addWindow (component);
237 }
238 }
239 else
240 {
241 if (tabComponent == nullptr && components.size() > numDocsBeforeTabsUsed)
242 {
245
246 auto temp = components;
247
248 for (auto& c : temp)
249 tabComponent->addTab (c->getName(), docColour, c, false);
250
251 resized();
252 }
253 else
254 {
255 if (tabComponent != nullptr)
256 tabComponent->addTab (component->getName(), docColour, component, false);
257 else
258 addAndMakeVisible (component);
259 }
260
261 setActiveDocument (component);
262 }
263
264 resized();
266 return true;
267}
268
270{
271 // Intellisense warns about component being uninitialised.
272 // I'm not sure how a function argument could be uninitialised.
274
275 component->removeComponentListener (this);
276
277 const bool shouldDelete = MultiDocHelpers::shouldDeleteComp (component);
278 component->getProperties().remove ("mdiDocumentDelete_");
279 component->getProperties().remove ("mdiDocumentBkg_");
280
281 if (mode == FloatingWindows)
282 {
283 for (auto* child : getChildren())
284 {
285 if (auto* dw = dynamic_cast<MultiDocumentPanelWindow*> (child))
286 {
287 if (dw->getContentComponent() == component)
288 {
289 std::unique_ptr<MultiDocumentPanelWindow> (dw)->clearContentComponent();
290 break;
291 }
292 }
293 }
294
295 if (shouldDelete)
296 delete component;
297
298 components.removeFirstMatchingValue (component);
299
300 if (isFullscreenWhenOneDocument() && components.size() == 1)
301 {
302 for (int i = getNumChildComponents(); --i >= 0;)
303 {
304 std::unique_ptr<MultiDocumentPanelWindow> dw (dynamic_cast<MultiDocumentPanelWindow*> (getChildComponent (i)));
305
306 if (dw != nullptr)
307 dw->clearContentComponent();
308 }
309
310 addAndMakeVisible (components.getFirst());
311 }
312 }
313 else
314 {
315 jassert (components.indexOf (component) >= 0);
316
317 if (tabComponent != nullptr)
318 {
319 for (int i = tabComponent->getNumTabs(); --i >= 0;)
320 if (tabComponent->getTabContentComponent (i) == component)
321 tabComponent->removeTab (i);
322 }
323 else
324 {
325 removeChildComponent (component);
326 }
327
328 if (shouldDelete)
329 delete component;
330
331 if (tabComponent != nullptr && tabComponent->getNumTabs() <= numDocsBeforeTabsUsed)
332 tabComponent.reset();
333
334 components.removeFirstMatchingValue (component);
335
336 if (components.size() > 0 && tabComponent == nullptr)
337 addAndMakeVisible (components.getFirst());
338 }
339
340 resized();
341
342 // This ensures that the active tab is painted properly when a tab is closed!
343 if (auto* activeComponent = getActiveDocument())
344 setActiveDocument (activeComponent);
345
347
349}
350
351#if JUCE_MODAL_LOOPS_PERMITTED
352bool MultiDocumentPanel::closeDocument (Component* component,
353 const bool checkItsOkToCloseFirst)
354{
355 // Intellisense warns about component being uninitialised.
356 // I'm not sure how a function argument could be uninitialised.
358
359 if (component == nullptr)
360 return true;
361
362 if (components.contains (component))
363 {
364 if (checkItsOkToCloseFirst && ! tryToCloseDocument (component))
365 return false;
366
367 closeDocumentInternal (component);
368 }
369 else
370 {
372 }
373
374 return true;
375
377}
378#endif
379
381 const bool checkItsOkToCloseFirst,
382 std::function<void (bool)> callback)
383{
384 // Intellisense warns about component being uninitialised.
385 // I'm not sure how a function argument could be uninitialised.
387
388 if (component == nullptr)
389 {
390 if (callback != nullptr)
391 callback (true);
392
393 return;
394 }
395
396 if (components.contains (component))
397 {
398 if (checkItsOkToCloseFirst)
399 {
400 tryToCloseDocumentAsync (component,
401 [parent = SafePointer<MultiDocumentPanel> { this }, component, callback] (bool closedSuccessfully)
402 {
403 if (parent == nullptr)
404 return;
405
406 if (closedSuccessfully)
407 parent->closeDocumentInternal (component);
408
409 if (callback != nullptr)
410 callback (closedSuccessfully);
411 });
412
413 return;
414 }
415
416 closeDocumentInternal (component);
417 }
418 else
419 {
421 }
422
423 if (callback != nullptr)
424 callback (true);
425
427}
428
433
434Component* MultiDocumentPanel::getDocument (const int index) const noexcept
435{
436 return components [index];
437}
438
440{
441 if (mode == FloatingWindows)
442 {
443 for (auto* child : getChildren())
444 if (auto* dw = dynamic_cast<MultiDocumentPanelWindow*> (child))
445 if (dw->isActiveWindow())
446 return dw->getContentComponent();
447 }
448
449 return components.getLast();
450}
451
453{
454 jassert (component != nullptr);
455
456 if (mode == FloatingWindows)
457 {
458 component = getContainerComp (component);
459
460 if (component != nullptr)
461 component->toFront (true);
462 }
463 else if (tabComponent != nullptr)
464 {
465 jassert (components.indexOf (component) >= 0);
466
467 for (int i = tabComponent->getNumTabs(); --i >= 0;)
468 {
469 if (tabComponent->getTabContentComponent (i) == component)
470 {
471 tabComponent->setCurrentTabIndex (i);
472 break;
473 }
474 }
475 }
476 else
477 {
478 component->grabKeyboardFocus();
479 }
480}
481
485
487{
488 maximumNumDocuments = newNumber;
489}
490
492{
493 numDocsBeforeTabsUsed = shouldUseTabs ? 1 : 0;
494}
495
500
501//==============================================================================
503{
504 if (mode != newLayoutMode)
505 {
506 mode = newLayoutMode;
507
508 if (mode == FloatingWindows)
509 {
510 tabComponent.reset();
511 }
512 else
513 {
514 for (int i = getNumChildComponents(); --i >= 0;)
515 {
516 std::unique_ptr<MultiDocumentPanelWindow> dw (dynamic_cast<MultiDocumentPanelWindow*> (getChildComponent (i)));
517
518 if (dw != nullptr)
519 {
520 dw->getContentComponent()->getProperties().set ("mdiDocumentPos_", dw->getWindowStateAsString());
521 dw->clearContentComponent();
522 }
523 }
524 }
525
526 resized();
527
528 auto tempComps = components;
529 components.clear();
530
531 for (auto* c : tempComps)
532 addDocument (c,
533 Colour ((uint32) static_cast<int> (c->getProperties().getWithDefault ("mdiDocumentBkg_", (int) Colours::white.getARGB()))),
535 }
536}
537
539{
540 if (backgroundColour != newBackgroundColour)
541 {
542 backgroundColour = newBackgroundColour;
543 setOpaque (newBackgroundColour.isOpaque());
544 repaint();
545 }
546}
547
548//==============================================================================
550{
551 g.fillAll (backgroundColour);
552}
553
555{
557 {
558 for (auto* child : getChildren())
559 child->setBounds (getLocalBounds());
560 }
561
562 setWantsKeyboardFocus (components.size() == 0);
563}
564
566{
567 if (mode == FloatingWindows)
568 {
569 for (auto* child : getChildren())
570 if (auto* dw = dynamic_cast<MultiDocumentPanelWindow*> (child))
571 if (dw->getContentComponent() == c)
572 return dw;
573 }
574
575 return c;
576}
577
579{
580 if (mode == FloatingWindows)
581 {
582 for (auto* child : getChildren())
583 if (auto* dw = dynamic_cast<MultiDocumentPanelWindow*> (child))
584 dw->setName (dw->getContentComponent()->getName());
585 }
586 else if (tabComponent != nullptr)
587 {
588 for (int i = tabComponent->getNumTabs(); --i >= 0;)
589 tabComponent->setTabName (i, tabComponent->getTabContentComponent (i)->getName());
590 }
591}
592
594{
595 auto oldList = components;
596
597 if (mode == FloatingWindows)
598 {
599 components.clear();
600
601 for (auto* child : getChildren())
602 if (auto* dw = dynamic_cast<MultiDocumentPanelWindow*> (child))
603 components.add (dw->getContentComponent());
604 }
605 else
606 {
607 if (tabComponent != nullptr)
608 {
609 if (auto* current = tabComponent->getCurrentContentComponent())
610 {
611 components.removeFirstMatchingValue (current);
612 components.add (current);
613 }
614 }
615 }
616
617 if (components != oldList)
619}
620
621} // namespace juce
#define noexcept
Definition DistrhoDefines.h:72
Definition juce_Colour.h:38
bool isOpaque() const noexcept
Definition juce_Colour.cpp:312
uint32 getARGB() const noexcept
Definition juce_Colour.cpp:301
Definition juce_Component.h:2287
Definition juce_Component.h:36
void removeComponentListener(ComponentListener *listenerToRemove)
Definition juce_Component.cpp:2337
int getNumChildComponents() const noexcept
Definition juce_Component.cpp:1643
void grabKeyboardFocus()
Definition juce_Component.cpp:2995
void toFront(bool shouldAlsoGainKeyboardFocus)
Definition juce_Component.cpp:954
void addComponentListener(ComponentListener *newListener)
Definition juce_Component.cpp:2323
void addAndMakeVisible(Component *child, int zOrder=-1)
Definition juce_Component.cpp:1554
void setOpaque(bool shouldBeOpaque)
Definition juce_Component.cpp:829
void repaint()
Definition juce_Component.cpp:1917
Component() noexcept
Definition juce_Component.cpp:517
NamedValueSet & getProperties() noexcept
Definition juce_Component.h:2209
void removeChildComponent(Component *childToRemove)
Definition juce_Component.cpp:1569
Component * getChildComponent(int index) const noexcept
Definition juce_Component.cpp:1648
TargetClass * findParentComponentOfClass() const
Definition juce_Component.h:813
void setWantsKeyboardFocus(bool wantsFocus) noexcept
Definition juce_Component.cpp:2842
Rectangle< int > getLocalBounds() const noexcept
Definition juce_Component.cpp:2283
virtual void broughtToFront()
Definition juce_Component.cpp:2751
const Array< Component * > & getChildren() const noexcept
Definition juce_Component.h:685
String getName() const noexcept
Definition juce_Component.h:76
void activeWindowStatusChanged() override
Definition juce_DocumentWindow.cpp:335
DocumentWindow(const String &name, Colour backgroundColour, int requiredButtons, bool addToDesktop=true)
Definition juce_DocumentWindow.cpp:48
@ closeButton
Definition juce_DocumentWindow.h:66
@ maximiseButton
Definition juce_DocumentWindow.h:65
Definition juce_GraphicsContext.h:45
Definition juce_MultiDocumentPanel.h:90
void setLayoutMode(LayoutMode newLayoutMode)
Definition juce_MultiDocumentPanel.cpp:502
virtual MultiDocumentPanelWindow * createNewDocumentWindow()
Definition juce_MultiDocumentPanel.cpp:170
int numDocsBeforeTabsUsed
Definition juce_MultiDocumentPanel.h:372
void componentNameChanged(Component &) override
Definition juce_MultiDocumentPanel.cpp:578
LayoutMode mode
Definition juce_MultiDocumentPanel.h:368
int maximumNumDocuments
Definition juce_MultiDocumentPanel.h:372
void setMaximumNumDocuments(int maximumNumDocuments)
Definition juce_MultiDocumentPanel.cpp:486
Component * getDocument(int index) const noexcept
Definition juce_MultiDocumentPanel.cpp:434
virtual void tryToCloseDocumentAsync(Component *component, std::function< void(bool)> callback)=0
friend class MultiDocumentPanelWindow
Definition juce_MultiDocumentPanel.h:362
int getNumDocuments() const noexcept
Definition juce_MultiDocumentPanel.cpp:429
void useFullscreenWhenOneDocument(bool shouldUseTabs)
Definition juce_MultiDocumentPanel.cpp:491
void paint(Graphics &) override
Definition juce_MultiDocumentPanel.cpp:549
Colour backgroundColour
Definition juce_MultiDocumentPanel.h:371
Component * getActiveDocument() const noexcept
Definition juce_MultiDocumentPanel.cpp:439
std::unique_ptr< TabbedComponent > tabComponent
Definition juce_MultiDocumentPanel.h:370
MultiDocumentPanel()
Definition juce_MultiDocumentPanel.cpp:93
void setActiveDocument(Component *component)
Definition juce_MultiDocumentPanel.cpp:452
void updateOrder()
Definition juce_MultiDocumentPanel.cpp:593
void setBackgroundColour(Colour newBackgroundColour)
Definition juce_MultiDocumentPanel.cpp:538
void closeDocumentAsync(Component *component, bool checkItsOkToCloseFirst, std::function< void(bool)> callback)
Definition juce_MultiDocumentPanel.cpp:380
void resized() override
Definition juce_MultiDocumentPanel.cpp:554
Array< Component * > components
Definition juce_MultiDocumentPanel.h:369
bool isFullscreenWhenOneDocument() const noexcept
Definition juce_MultiDocumentPanel.cpp:496
LayoutMode
Definition juce_MultiDocumentPanel.h:258
@ FloatingWindows
Definition juce_MultiDocumentPanel.h:259
@ MaximisedWindowsWithTabs
Definition juce_MultiDocumentPanel.h:260
static void closeLastDocumentRecursive(SafePointer< MultiDocumentPanel >, bool, std::function< void(bool)>)
Definition juce_MultiDocumentPanel.cpp:125
bool addDocument(Component *component, Colour backgroundColour, bool deleteWhenRemoved)
Definition juce_MultiDocumentPanel.cpp:202
Component * getContainerComp(Component *) const
Definition juce_MultiDocumentPanel.cpp:565
void closeDocumentInternal(Component *)
Definition juce_MultiDocumentPanel.cpp:269
void addWindow(Component *)
Definition juce_MultiDocumentPanel.cpp:175
~MultiDocumentPanel() override
Definition juce_MultiDocumentPanel.cpp:98
void closeAllDocumentsAsync(bool checkItsOkToCloseFirst, std::function< void(bool)> callback)
Definition juce_MultiDocumentPanel.cpp:156
virtual void activeDocumentChanged()
Definition juce_MultiDocumentPanel.cpp:482
void activeWindowStatusChanged() override
Definition juce_MultiDocumentPanel.cpp:56
MultiDocumentPanel * getOwner() const noexcept
Definition juce_MultiDocumentPanel.cpp:74
void maximiseButtonPressed() override
Definition juce_MultiDocumentPanel.cpp:40
void broughtToFront() override
Definition juce_MultiDocumentPanel.cpp:62
~MultiDocumentPanelWindow() override
Definition juce_MultiDocumentPanel.cpp:35
void updateOrder()
Definition juce_MultiDocumentPanel.cpp:68
void closeButtonPressed() override
Definition juce_MultiDocumentPanel.cpp:48
MultiDocumentPanelWindow(Colour backgroundColour)
Definition juce_MultiDocumentPanel.cpp:29
bool set(const Identifier &name, const var &newValue)
Definition juce_NamedValueSet.cpp:183
bool remove(const Identifier &name)
Definition juce_NamedValueSet.cpp:214
Definition juce_ResizableWindow.h:52
Component * getContentComponent() const noexcept
Definition juce_ResizableWindow.h:239
Definition juce_String.h:53
Definition juce_TabbedButtonBar.h:155
TabbedComponent(TabbedButtonBar::Orientation orientation)
Definition juce_TabbedComponent.cpp:89
int g
Definition inflate.c:1573
register unsigned i
Definition inflate.c:1575
unsigned x[BMAX+1]
Definition inflate.c:1586
static uintptr_t parent
Definition pugl.h:1644
#define JUCE_BEGIN_IGNORE_WARNINGS_MSVC(warnings)
Definition juce_CompilerWarnings.h:198
#define JUCE_END_IGNORE_WARNINGS_MSVC
Definition juce_CompilerWarnings.h:199
#define jassert(expression)
#define jassertfalse
const Colour white
Definition juce_Colours.h:180
Definition juce_MultiDocumentPanel.cpp:107
static bool shouldDeleteComp(Component *const c)
Definition juce_MultiDocumentPanel.cpp:108
Definition carla_juce.cpp:31
unsigned int uint32
Definition juce_MathsFunctions.h:45
#define true
Definition ordinals.h:82
#define false
Definition ordinals.h:83
Definition juce_MultiDocumentPanel.cpp:81
void currentTabChanged(int, const String &) override
Definition juce_MultiDocumentPanel.cpp:84
TabbedComponentInternal()
Definition juce_MultiDocumentPanel.cpp:82
RECT const char void(* callback)(const char *droppath))) SWELL_API_DEFINE(BOOL
Definition swell-functions.h:1004
return c
Definition crypt.c:175
if(GLOBAL(newzip))
Definition crypt.c:475
return
Definition extract.c:2364
#define const
Definition zconf.h:137