I’ve had a real struggle configuring a 7-year-old JUCE app to handle this.
Even creating a fresh Projucer project I had to fiddle a lot.
Shouldn’t this be the out-of-the-box / hello-world / default? Seems the most natural/expected behaviour to me.
Sharing my solution mainly as it doesn’t feel comfortable yet, so if I’m missing something obvious, please do say!
So what I did first was “update” my boilerplate code by creating a fresh project from the ProJucer and ripping code from Main.cpp and MainComponent.{cpp/h}.
NOTE: One thing I realized was that simultaneously having open iOS and macOS XCode windows (opened from the Projucer exporters) was messing with flags like JUCE_IOS – A #if JUCE_IOS block was mis-colouring (and mis-executing). To fix, I needed to close all XCode windows and re-export the target-of-interest.
Ok so here’s the working code:
class MainWindow : public juce::DocumentWindow
{
public:
MainWindow(juce::String name)
: DocumentWindow(
name,
juce::Desktop::getInstance().getDefaultLookAndFeel().findColour(
juce::ResizableWindow::backgroundColourId
),
DocumentWindow::allButtons
) // above here is all boilerplate
{
setUsingNativeTitleBar (true);
#if JUCE_IOS || JUCE_ANDROID
bool resizeToFitWhenContentChangesSize = false;
#else
bool resizeToFitWhenContentChangesSize = true;
#endif
setContentOwned (new MainContentComponent(), resizeToFitWhenContentChangesSize );
#if JUCE_IOS || JUCE_ANDROID
setFullScreen (true);
#else
setResizable (true, true);
// setSize(1024, 768);
centreWithSize (getWidth(), getHeight());
#endif
setVisible (true);
}
Shouldn’t something like this be in the boilerplate that gets auto-generated by the Projucer?
Also to make it work for desktop, I have to add a setSize to the END of my MainComponent’s c’tor:
class MainContentComponent : public Component
,private Button::Listener
,private MidiInputCallback
,public ActionListener
{
private:
SharedResourcePointer<AudioSettings> sharedAudioSettings;
TextButton btnInput, btnOutput;
std::unique_ptr<PiSynthPlayer> pSynthPlayer;
std::unique_ptr<Wheel> pWheel;
std::unique_ptr<GameLogic> pGameLogic;
public:
MainContentComponent()
{
// setSize (800, 600);
addAndMakeVisible(&btnInput);
btnInput.setButtonText("Input");
btnInput.addListener(this);
btnInput.setColour(TextButton::buttonColourId, Colours::red);
addAndMakeVisible(&btnOutput);
btnOutput.setButtonText("Output");
btnOutput.addListener(this);
btnOutput.setColour(TextButton::buttonColourId, Colours::green);
// - - - - - - -
pWheel = std::make_unique<Wheel>();
addAndMakeVisible(pWheel.get());
pWheel->addActionListener(this);
pWheel->setVisible(true);
pWheel->toFront(true);
// - - - - - - -
pSynthPlayer = std::make_unique<PiSynthPlayer>(sharedAudioSettings->getOutputDeviceManager());
sharedAudioSettings->getInputDeviceManager().setMidiInputDeviceEnabled(MidiInput::getAvailableDevices()[0].name, true);
sharedAudioSettings->getInputDeviceManager().addMidiInputDeviceCallback(String(""), this);
// - - - - - - -
pGameLogic = std::make_unique<GameLogic>(pWheel.get(), pSynthPlayer.get());
addAndMakeVisible(pGameLogic.get());
//setWantsKeyboardFocus(true); // also see paint()
#if JUCE_MAC
setSize(1024, 768);
#endif
}
The only relevant line in that last block is the setSize. But it needs to go at the end of the c’tor. If it goes at the start, I get an assertion error:
inline ValueType getWidth() const noexcept { return w; }
// line 133 of juce_Rectangle.h, EXC_BAD_ACCESS
I cannot figure out what’s the difference in putting it at the start/end of that c’tor.
Everything else seems to be components I’m adding in, and I don’t see how any of them could be affecting this crash.
Also it seems I have to setSize in the MainComponent.
If I try to do it in Main.cpp, like this:
#if JUCE_IOS || JUCE_ANDROID
setFullScreen (true);
#else
setResizable (true, true);
setSize(1024, 768);
centreWithSize (getWidth(), getHeight());
#endif
… I now get an assert fail in juce_ResizableWindow.cpp line 244:
void ResizableWindow::childBoundsChanged (Component* child)
{
if ((child == contentComponent) && (child != nullptr) && resizeToFitContent)
{
// not going to look very good if this component has a zero size..
jassert (child->getWidth() > 0);
Can anyone help me to tidy up my code? I would like for the skeleton of the app to be as clean as I can get it.
PS It might be useful to have IS_MOBILE and IS_DESKTOP #define-s which are guaranteed to exist as either 0 or 1. This would allow a more compact x = IS_MOBILE ? foo : bar syntax.
