tracktion-engine 3.0-10-g034fdde4aa5
Tracktion Engine — High level data model for audio applications

« « « Anklang Documentation
Loading...
Searching...
No Matches
tracktion_PluginWindowState.cpp
Go to the documentation of this file.
1 /*
2 ,--. ,--. ,--. ,--.
3 ,-' '-.,--.--.,--,--.,---.| |,-.,-' '-.`--' ,---. ,--,--, Copyright 2024
4 '-. .-'| .--' ,-. | .--'| /'-. .-',--.| .-. || \ Tracktion Software
5 | | | | \ '-' \ `--.| \ \ | | | |' '-' '| || | Corporation
6 `---' `--' `--`--'`---'`--'`--' `---' `--' `---' `--''--' www.tracktion.com
7
8 Tracktion Engine uses a GPL/commercial licence - see LICENCE.md for details.
9*/
10
11namespace tracktion { inline namespace engine
12{
13
14static bool isDialogOpen()
15{
16 auto& mm = *juce::ModalComponentManager::getInstance();
17 if (mm.getNumModalComponents() > 0)
18 return true;
19
20 for (int i = juce::TopLevelWindow::getNumTopLevelWindows(); --i >= 0;)
22 if (dynamic_cast<juce::AlertWindow*> (w))
23 return true;
24
25 return false;
26}
27
28PluginWindowState::PluginWindowState (Edit& e)
29 : edit (e),
30 engine (e.engine),
31 windowLocked (engine.getPluginManager().areGUIsLockedByDefault())
32{
33}
34
35void PluginWindowState::deleteWindow()
36{
37 pluginWindow.reset();
38}
39
40void PluginWindowState::incRefCount()
41{
42 TRACKTION_ASSERT_MESSAGE_THREAD
43 ++windowShowerCount;
44 startTimer (100);
45}
46
47void PluginWindowState::decRefCount()
48{
49 TRACKTION_ASSERT_MESSAGE_THREAD
50 --windowShowerCount;
51 startTimer (100);
52}
53
54void PluginWindowState::showWindowExplicitly()
55{
56 TRACKTION_ASSERT_MESSAGE_THREAD
57 wasExplicitlyClosed = false;
58 stopTimer();
59 showWindow();
60}
61
62void PluginWindowState::closeWindowExplicitly()
63{
64 TRACKTION_ASSERT_MESSAGE_THREAD
65
66 if (pluginWindow && pluginWindow->isVisible())
67 {
68 wasExplicitlyClosed = true;
69 deleteWindow();
70 stopTimer();
71 }
72}
73
74bool PluginWindowState::isWindowShowing() const
75{
76 return pluginWindow != nullptr && pluginWindow->isVisible();
77}
78
79void PluginWindowState::recreateWindowIfShowing()
80{
81 deleteWindow();
82 startTimer (100);
83}
84
85void PluginWindowState::hideWindowForShutdown()
86{
87 deleteWindow();
88 stopTimer();
89}
90
91void PluginWindowState::pickDefaultWindowBounds()
92{
93 lastWindowBounds = { 100, 100, 600, 500 };
94
95 if (auto focused = juce::Component::getCurrentlyFocusedComponent())
96 lastWindowBounds.setPosition (focused->getTopLevelComponent()->getPosition()
97 + juce::Point<int> (80, 80));
98}
99
100void PluginWindowState::showWindow()
101{
102 if (isDialogOpen())
103 return;
104
105 if (! pluginWindow)
106 {
107 // Ensure at least 40px of the window is on screen
108 const auto displayRects = []
109 {
110 juce::RectangleList<int> trimmedDisplays;
111
112 for (auto rect : juce::Desktop::getInstance().getDisplays().getRectangleList (true))
113 trimmedDisplays.addWithoutMerging (rect.withTrimmedLeft (100).withTrimmedRight (100).withTrimmedBottom (100));
114
115 return trimmedDisplays;
116 }();
117
118 const bool windowBoundsIsOnScreen = displayRects.intersectsRectangle (lastWindowBounds);
119
120 if (lastWindowBounds.isEmpty() || ! windowBoundsIsOnScreen)
121 pickDefaultWindowBounds();
122
123 juce::WeakReference<juce::Component> oldFocus (juce::Component::getCurrentlyFocusedComponent());
124 pluginWindow = engine.getUIBehaviour().createPluginWindow (*this);
125
126 if (oldFocus != nullptr)
127 oldFocus->grabKeyboardFocus();
128 }
129
130 if (pluginWindow)
131 {
132 windowOpenTime = juce::Time::getCurrentTime();
133 pluginWindow->setVisible (true);
134 pluginWindow->toFront (false);
135 }
136}
137
138void PluginWindowState::pluginClicked (const juce::MouseEvent& e)
139{
140 bool isShowing = isWindowShowing();
141
142 if (e.getNumberOfClicks() >= 2)
143 {
144 if ((juce::Time::getCurrentTime() - windowOpenTime).inMilliseconds() < 300)
145 return;
146
147 if (isShowing)
148 closeWindowExplicitly();
149 else
150 showWindowExplicitly();
151 }
152 else if (! (isShowing || engine.getPluginManager().doubleClickToOpenWindows()))
153 {
154 showWindowExplicitly();
155 }
156}
157
158void PluginWindowState::timerCallback()
159{
160 stopTimer();
161
162 if (windowShowerCount > 0)
163 {
164 if ((pluginWindow == nullptr || ! pluginWindow->isVisible())
165 && ! (engine.getPluginManager().doubleClickToOpenWindows() || wasExplicitlyClosed))
166 showWindow();
167 }
168 else if (! windowLocked)
169 {
170 deleteWindow();
171 }
172}
173
174}} // namespace tracktion { inline namespace engine
int getNumberOfClicks() const noexcept
bool intersectsRectangle(RectangleType rectangleToCheck) const noexcept
static Time JUCE_CALLTYPE getCurrentTime() noexcept
static int getNumTopLevelWindows() noexcept
static TopLevelWindow * getTopLevelWindow(int index) noexcept