Skip to content

Commit 23e7bf8

Browse files
authored
Merge pull request #353 from TEAMuP-dev/bug/min-control-size
Sizing constraints and reorganization for better behavior at boundaries.
2 parents 31f3eab + dc34d9f commit 23e7bf8

12 files changed

Lines changed: 668 additions & 167 deletions

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ target_sources(${PROJECT_NAME}
9191
src/gui/SliderWithLabel.h
9292
src/gui/ComboBoxWithLabel.h
9393
src/gui/HoverHandler.h
94+
src/gui/ControlComponent.h
95+
src/gui/ToggleWithLabel.h
9496

9597
src/media/MediaDisplayComponent.cpp
9698
src/media/AudioDisplayComponent.cpp

src/Main.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,9 +227,13 @@ class GuiAppApplication : public JUCEApplication, public FocusChangeListener
227227
windowIdentifier(name.replaceCharacters(" :", "__"))
228228
{
229229
setUsingNativeTitleBar(true);
230-
setContentOwned(new MainComponent(), true);
230+
MainComponent* mainComp = new MainComponent();
231+
setContentOwned(mainComp, true);
231232
setResizable(true, true);
232233

234+
setConstrainer(&constrainer);
235+
mainComp->updateWindowConstraints();
236+
233237
// Try to restore saved position and size
234238
restoreWindowPosition();
235239

@@ -359,6 +363,8 @@ class GuiAppApplication : public JUCEApplication, public FocusChangeListener
359363

360364
String windowIdentifier;
361365

366+
ComponentBoundsConstrainer constrainer;
367+
362368
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(HARPWindow)
363369
};
364370

src/MainComponent.cpp

Lines changed: 101 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,29 @@ MainComponent::MainComponent()
88

99
initializeMenuBar();
1010

11+
mainModelTab.addChangeListener(this);
12+
1113
addAndMakeVisible(mainModelTab);
1214
addAndMakeVisible(statusAreaWidget);
1315
addAndMakeVisible(mediaClipboardWidget);
1416

1517
showStatusArea = Settings::getBoolValue("view.showStatusArea", true);
1618
showMediaClipboard = Settings::getBoolValue("view.showMediaClipboard", false);
1719

18-
sharedTokens->initializeAPIKeys();
20+
requiredWindowWidth = minimumWindowWidth;
21+
requiredWindowHeight = minimumWindowHeight;
22+
setSize(requiredWindowWidth, requiredWindowHeight);
1923

20-
setSize(800, 2000);
24+
sharedTokens->initializeAPIKeys();
2125

2226
statusMessage->setMessage("Welcome to HARP!");
2327
}
2428

25-
MainComponent::~MainComponent() { deinitializeMenuBar(); }
29+
MainComponent::~MainComponent()
30+
{
31+
deinitializeMenuBar();
32+
mainModelTab.removeChangeListener(this);
33+
}
2634

2735
void MainComponent::paint(Graphics& g)
2836
{
@@ -48,7 +56,7 @@ void MainComponent::resized()
4856

4957
if (showStatusArea)
5058
{
51-
mainPanel.items.add(FlexItem(statusAreaWidget).withHeight(100));
59+
mainPanel.items.add(FlexItem(statusAreaWidget).withHeight(statusAreaHeight));
5260
}
5361
else
5462
{
@@ -59,7 +67,7 @@ void MainComponent::resized()
5967

6068
if (showMediaClipboard)
6169
{
62-
fullWindow.items.add(FlexItem(mediaClipboardWidget).withFlex(0.4));
70+
fullWindow.items.add(FlexItem(mediaClipboardWidget).withFlex(mediaClipboardFlex));
6371
}
6472
else
6573
{
@@ -69,6 +77,65 @@ void MainComponent::resized()
6977
fullWindow.performLayout(fullArea);
7078
}
7179

80+
void MainComponent::updateWindowConstraints()
81+
{
82+
if (auto* window = findParentComponentOfClass<DocumentWindow>())
83+
{
84+
// Compute percentage of total window width given to main panel
85+
const float mainPanelRatio = showMediaClipboard ? (1.0f / mediaClipboardScale) : 1.0f;
86+
87+
// Determine minimum width needed to display controls plus padding
88+
const int requiredMainPanelWidth =
89+
jmax(minimumMainPanelWidth,
90+
mainModelTab.getMinimumRequiredControlWidth() + minimumMainPanelHorPadding);
91+
// Determine current width of main panel
92+
const int mainPanelWidth = jmax(requiredMainPanelWidth, mainModelTab.getWidth());
93+
// Determine minimum height needed to display all model contents plus status widget
94+
const int requiredMainPanelHeight =
95+
mainModelTab.getMinimumRequiredHeightForWidth(mainPanelWidth)
96+
+ (showStatusArea ? statusAreaHeight : 0);
97+
98+
// Determine effective minimum width of entire window
99+
const int newRequiredWindowWidth = jmax(
100+
minimumWindowWidth, (int) std::ceil((float) requiredMainPanelWidth / mainPanelRatio));
101+
// Determine effective minimum height of entire window
102+
const int newRequiredWindowHeight =
103+
jmax(minimumWindowHeight, requiredMainPanelHeight + minimumMainPanelVertPadding);
104+
105+
auto* currentDisplay =
106+
Desktop::getInstance().getDisplays().getDisplayForRect(window->getScreenBounds());
107+
108+
const auto userArea =
109+
currentDisplay != nullptr
110+
? currentDisplay->userArea
111+
: Rectangle<int>(0, 0, newRequiredWindowWidth, newRequiredWindowHeight);
112+
113+
ComponentBoundsConstrainer* constrainer = window->getConstrainer();
114+
115+
constrainer->setMinimumSize(jmin(newRequiredWindowWidth, userArea.getWidth()),
116+
jmin(newRequiredWindowHeight, userArea.getHeight()));
117+
constrainer->setMaximumSize(userArea.getWidth(), userArea.getHeight());
118+
constrainer->setMinimumOnscreenAmounts(40, 40, 40, 40);
119+
120+
const bool constraintsDecreased = newRequiredWindowWidth < requiredWindowWidth
121+
|| newRequiredWindowHeight < requiredWindowHeight;
122+
123+
requiredWindowWidth = newRequiredWindowWidth;
124+
requiredWindowHeight = newRequiredWindowHeight;
125+
126+
auto bounds = window->getBounds();
127+
128+
window->setBoundsConstrained(bounds);
129+
130+
if (constraintsDecreased)
131+
{
132+
// Small hack allowing immediate shrinking when constraints decrease
133+
window->setBounds(bounds.withWidth(bounds.getWidth() + 1));
134+
window->setBounds(bounds);
135+
}
136+
}
137+
}
138+
72139
/* --File-- */
73140

74141
/**
@@ -110,9 +177,13 @@ void MainComponent::viewStatusAreaCallback()
110177
{
111178
// Determine which display contains HARP
112179
auto* currentDisplay =
113-
Desktop::getInstance().getDisplays().getDisplayForRect(getScreenBounds());
180+
Desktop::getInstance().getDisplays().getDisplayForRect(window->getScreenBounds());
181+
182+
// Get current bounds of top-level window
183+
Rectangle<int> windowBounds = window->getBounds();
114184

115-
int currentDisplayHeight;
185+
// Default display height to height of current window
186+
int currentDisplayHeight = windowBounds.getHeight();
116187

117188
if (currentDisplay != nullptr)
118189
{
@@ -126,20 +197,18 @@ void MainComponent::viewStatusAreaCallback()
126197
}
127198
}
128199

129-
// Get current bounds of top-level window
130-
Rectangle<int> windowBounds = window->getBounds();
131-
132200
if (showStatusArea)
133201
{
134202
// Scale bounds to extend window by height of status area
135-
windowBounds.setHeight(jmin(currentDisplayHeight, windowBounds.getHeight() + 100));
203+
windowBounds.setHeight(
204+
jmin(currentDisplayHeight, windowBounds.getHeight() + statusAreaHeight));
136205
}
137206
else
138207
{
139208
if (! window->isFullScreen())
140209
{
141210
// Scale bounds to reduce window to main height
142-
windowBounds.setHeight(windowBounds.getHeight() - 100);
211+
windowBounds.setHeight(windowBounds.getHeight() - statusAreaHeight);
143212
}
144213
}
145214

@@ -153,7 +222,7 @@ void MainComponent::viewStatusAreaCallback()
153222
// Send status message to add check to file menu
154223
commandManager.commandStatusChanged();
155224

156-
resized();
225+
updateWindowConstraints();
157226
}
158227

159228
void MainComponent::viewMediaClipboardCallback()
@@ -166,9 +235,13 @@ void MainComponent::viewMediaClipboardCallback()
166235
{
167236
// Determine which display contains HARP
168237
auto* currentDisplay =
169-
Desktop::getInstance().getDisplays().getDisplayForRect(getScreenBounds());
238+
Desktop::getInstance().getDisplays().getDisplayForRect(window->getScreenBounds());
239+
240+
// Get current bounds of top-level window
241+
Rectangle<int> windowBounds = window->getBounds();
170242

171-
int currentDisplayWidth;
243+
// Default display width to width of current window
244+
int currentDisplayWidth = windowBounds.getWidth();
172245

173246
if (currentDisplay != nullptr)
174247
{
@@ -182,23 +255,20 @@ void MainComponent::viewMediaClipboardCallback()
182255
}
183256
}
184257

185-
//int totalDesktopWidth = Desktop::getInstance().getDisplays().getDisplayForRect(getBounds())->totalArea.getWidth();
186-
187-
// Get current bounds of top-level window
188-
Rectangle<int> windowBounds = window->getBounds();
189-
190258
if (showMediaClipboard)
191259
{
192260
// Scale bounds to extend window by 40% of main width
193261
windowBounds.setWidth(
194-
jmin(currentDisplayWidth, static_cast<int>(1.4 * windowBounds.getWidth())));
262+
jmin(currentDisplayWidth,
263+
static_cast<int>(mediaClipboardScale * windowBounds.getWidth())));
195264
}
196265
else
197266
{
198267
if (! window->isFullScreen())
199268
{
200269
// Scale bounds to reduce window to main width
201-
windowBounds.setWidth(static_cast<int>(windowBounds.getWidth() / 1.4));
270+
windowBounds.setWidth(
271+
static_cast<int>(windowBounds.getWidth() / mediaClipboardScale));
202272
}
203273
}
204274

@@ -212,7 +282,7 @@ void MainComponent::viewMediaClipboardCallback()
212282
// Send status message to add check to file menu
213283
commandManager.commandStatusChanged();
214284

215-
resized();
285+
updateWindowConstraints();
216286
}
217287

218288
/* --Help-- */
@@ -281,3 +351,11 @@ void MainComponent::focusCallback()
281351
}
282352
}
283353
*/
354+
355+
void MainComponent::changeListenerCallback(ChangeBroadcaster* source)
356+
{
357+
if (source == &mainModelTab)
358+
{
359+
updateWindowConstraints();
360+
}
361+
}

src/MainComponent.h

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@
2424

2525
using namespace juce;
2626

27-
class MainComponent : public Component, public MenuBarModel, public ApplicationCommandTarget
27+
class MainComponent : public Component,
28+
public MenuBarModel,
29+
public ApplicationCommandTarget,
30+
private ChangeListener
2831

2932
{
3033
public:
@@ -70,6 +73,8 @@ class MainComponent : public Component, public MenuBarModel, public ApplicationC
7073
void paint(Graphics& g) override;
7174
void resized() override;
7275

76+
void updateWindowConstraints();
77+
7378
private:
7479
/* File Menu */
7580

@@ -87,9 +92,27 @@ class MainComponent : public Component, public MenuBarModel, public ApplicationC
8792

8893
// Miscellaneous
8994
//void focusCallback();
95+
void changeListenerCallback(ChangeBroadcaster* source);
9096

9197
/* Interface */
9298

99+
const int statusAreaHeight = 100;
100+
const float mediaClipboardFlex = 0.4f;
101+
const float mediaClipboardScale = 1.4f;
102+
103+
// Minimum size to ensure all controls remain visible and functional:
104+
// - WelcomeWindow popup is 480x500, needs padding
105+
// - Dropdown labels need adequate width
106+
// - Control Area needs space for sliders/toggles/textboxes
107+
const int minimumWindowWidth = 700;
108+
const int minimumWindowHeight = 500;
109+
const int minimumMainPanelWidth = 320;
110+
const int minimumMainPanelHorPadding = 32;
111+
const int minimumMainPanelVertPadding = 32;
112+
113+
int requiredWindowWidth;
114+
int requiredWindowHeight;
115+
93116
bool showStatusArea;
94117
bool showMediaClipboard;
95118

0 commit comments

Comments
 (0)