Skip to content

Commit

Permalink
Projucer: Ensure that new project windows are always fully onscreen
Browse files Browse the repository at this point in the history
  • Loading branch information
ed95 committed Dec 12, 2019
1 parent 1650b1c commit aeaae3b
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 95 deletions.
2 changes: 1 addition & 1 deletion extras/Projucer/Source/Application/jucer_Application.cpp
Expand Up @@ -1165,7 +1165,7 @@ void ProjucerApplication::createNewProject()
auto* mw = mainWindowList.getOrCreateEmptyWindow();
mw->showStartPage();

mainWindowList.avoidSuperimposedWindows (mw);
mainWindowList.checkWindowBounds (mw);
}

void ProjucerApplication::createNewProjectFromClipboard()
Expand Down
181 changes: 94 additions & 87 deletions extras/Projucer/Source/Application/jucer_MainWindow.cpp
Expand Up @@ -50,27 +50,29 @@ MainWindow::MainWindow()
setResizable (true, false);
centreWithSize (800, 600);

ApplicationCommandManager& commandManager = ProjucerApplication::getCommandManager();
auto& commandManager = ProjucerApplication::getCommandManager();

// Register all the app commands..
commandManager.registerAllCommandsForTarget (this);
commandManager.registerAllCommandsForTarget (getProjectContentComponent());
auto registerAllAppCommands = [&]
{
commandManager.registerAllCommandsForTarget (this);
commandManager.registerAllCommandsForTarget (getProjectContentComponent());
};

// update key mappings..
auto updateAppKeyMappings = [&]
{
commandManager.getKeyMappings()->resetToDefaultMappings();

if (auto keys = getGlobalProperties().getXmlValue ("keyMappings"))
commandManager.getKeyMappings()->restoreFromXml (*keys);

addKeyListener (commandManager.getKeyMappings());
}
};

// don't want the window to take focus when the title-bar is clicked..
setWantsKeyboardFocus (false);
registerAllAppCommands();
updateAppKeyMappings();

setWantsKeyboardFocus (false);
getLookAndFeel().setColour (ColourSelector::backgroundColourId, Colours::transparentBlack);

projectNameValue.addListener (this);

setResizeLimits (600, 500, 32000, 32000);
Expand All @@ -83,8 +85,6 @@ MainWindow::~MainWindow()
#endif

removeKeyListener (ProjucerApplication::getCommandManager().getKeyMappings());

// save the current size and position to our settings file..
getGlobalProperties().setValue ("lastMainWindowPos", getWindowStateAsString());

clearContentComponent();
Expand All @@ -97,7 +97,6 @@ void MainWindow::createProjectContentCompIfNeeded()
{
clearContentComponent();
setContentOwned (new ProjectContentComponent(), false);
jassert (getProjectContentComponent() != nullptr);
}
}

Expand All @@ -119,12 +118,10 @@ void MainWindow::setTitleBarIcon()

void MainWindow::makeVisible()
{
restoreWindowPosition();
setVisible (true);
addToDesktop(); // (must add before restoring size so that fullscreen will work)
addToDesktop();
restoreWindowPosition();
setTitleBarIcon();

getContentComponent()->grabKeyboardFocus();
}

Expand All @@ -138,14 +135,12 @@ void MainWindow::closeButtonPressed()
ProjucerApplication::getApp().mainWindowList.closeWindow (this);
}

bool MainWindow::closeProject (Project* project, bool askUserToSave)
bool MainWindow::closeCurrentProject (bool askUserToSave)
{
jassert (project == currentProject.get() && project != nullptr);

if (project == nullptr)
if (currentProject == nullptr)
return true;

project->getStoredProperties().setValue (getProjectWindowPosName(), getWindowStateAsString());
currentProject->getStoredProperties().setValue (getProjectWindowPosName(), getWindowStateAsString());

if (auto* pcc = getProjectContentComponent())
{
Expand All @@ -154,28 +149,24 @@ bool MainWindow::closeProject (Project* project, bool askUserToSave)
pcc->hideEditor();
}

if (! ProjucerApplication::getApp().openDocumentManager.closeAllDocumentsUsingProject (*project, askUserToSave))
return false;

if (! askUserToSave || (project->saveIfNeededAndUserAgrees() == FileBasedDocument::savedOk))
if (ProjucerApplication::getApp().openDocumentManager
.closeAllDocumentsUsingProject (*currentProject, askUserToSave))
{
setProject (nullptr);
return true;
if (! askUserToSave || (currentProject->saveIfNeededAndUserAgrees() == FileBasedDocument::savedOk))
{
setProject (nullptr);
return true;
}
}

return false;
}

bool MainWindow::closeCurrentProject()
{
return currentProject == nullptr || closeProject (currentProject.get());
}

void MainWindow::moveProject (File newProjectFileToOpen)
{
auto openInIDE = currentProject->shouldOpenInIDEAfterSaving();

closeProject (currentProject.get(), false);
closeCurrentProject (false);
openFile (newProjectFileToOpen);

if (currentProject != nullptr)
Expand All @@ -186,21 +177,25 @@ void MainWindow::moveProject (File newProjectFileToOpen)
}
}

void MainWindow::setProject (Project* newProject)
void MainWindow::setProject (std::unique_ptr<Project> newProject)
{
createProjectContentCompIfNeeded();
getProjectContentComponent()->setProject (newProject);
currentProject.reset (newProject);

if (currentProject != nullptr)
projectNameValue.referTo (currentProject->getProjectValue (Ids::name));
else
if (newProject == nullptr)
{
getProjectContentComponent()->setProject (nullptr);
projectNameValue.referTo (Value());

if (newProject != nullptr)
currentProject.reset();
}
else
{
currentProject = std::move (newProject);

createProjectContentCompIfNeeded();
getProjectContentComponent()->setProject (currentProject.get());
projectNameValue.referTo (currentProject->getProjectValue (Ids::name));

if (auto* peer = getPeer())
peer->setRepresentedFile (newProject->getFile());
peer->setRepresentedFile (currentProject->getFile());
}

ProjucerApplication::getCommandManager().commandStatusChanged();
Expand Down Expand Up @@ -232,20 +227,16 @@ bool MainWindow::openFile (const File& file)

if (file.hasFileExtension (Project::projectFileExtension))
{
std::unique_ptr<Project> newDoc (new Project (file));

auto newDoc = std::make_unique<Project> (file);
auto result = newDoc->loadFrom (file, true);

if (result.wasOk() && closeCurrentProject())
if (result.wasOk() && closeCurrentProject (true))
{
setProject (newDoc.get());
newDoc.release()->setChangedFlag (false);
setProject (std::move (newDoc));
currentProject->setChangedFlag (false);

jassert (getProjectContentComponent() != nullptr);
getProjectContentComponent()->reloadLastOpenDocuments();

if (auto* p = getProject())
p->updateDeprecatedProjectSettingsInteractively();
currentProject->updateDeprecatedProjectSettingsInteractively();

return true;
}
Expand Down Expand Up @@ -606,7 +597,7 @@ bool MainWindowList::askAllWindowsToClose()

while (windows.size() > 0)
{
if (! windows[0]->closeCurrentProject())
if (! windows[0]->closeCurrentProject (true))
return false;

windows.remove (0);
Expand All @@ -617,7 +608,7 @@ bool MainWindowList::askAllWindowsToClose()

void MainWindowList::createWindowIfNoneAreOpen()
{
if (windows.size() == 0)
if (windows.isEmpty())
createNewMainWindow()->showStartPage();
}

Expand All @@ -633,7 +624,7 @@ void MainWindowList::closeWindow (MainWindow* w)
else
#endif
{
if (w->closeCurrentProject())
if (w->closeCurrentProject (true))
{
windows.removeObject (w);
saveCurrentlyOpenProjectList();
Expand Down Expand Up @@ -689,22 +680,20 @@ bool MainWindowList::openFile (const File& file, bool openInBackground)
WeakReference<Component> previousFrontWindow (getFrontmostWindow());

auto* w = getOrCreateEmptyWindow();
bool ok = w->openFile (file);

if (ok)
if (w->openFile (file))
{
w->makeVisible();
avoidSuperimposedWindows (w);
}
else
{
closeWindow (w);
}
checkWindowBounds (w);

if (openInBackground && previousFrontWindow != nullptr)
previousFrontWindow->toFront (true);
if (openInBackground && previousFrontWindow != nullptr)
previousFrontWindow->toFront (true);

return ok;
return true;
}

closeWindow (w);
return false;
}

if (getFrontmostWindow()->tryToOpenPIP (file))
Expand All @@ -718,11 +707,8 @@ bool MainWindowList::openFile (const File& file, bool openInBackground)

MainWindow* MainWindowList::createNewMainWindow()
{
auto w = new MainWindow();
windows.add (w);
w->restoreWindowPosition();
avoidSuperimposedWindows (w);
return w;
windows.add (new MainWindow());
return windows.getLast();
}

MainWindow* MainWindowList::getFrontmostWindow (bool createIfNotFound)
Expand All @@ -732,8 +718,9 @@ MainWindow* MainWindowList::getFrontmostWindow (bool createIfNotFound)
if (createIfNotFound)
{
auto* w = createNewMainWindow();
avoidSuperimposedWindows (w);
w->makeVisible();
checkWindowBounds (w);

return w;
}

Expand Down Expand Up @@ -784,29 +771,49 @@ MainWindow* MainWindowList::getMainWindowForFile (const File& file)
return nullptr;
}

void MainWindowList::avoidSuperimposedWindows (MainWindow* const mw)
void MainWindowList::checkWindowBounds (MainWindow* windowToCheck)
{
for (int i = windows.size(); --i >= 0;)
auto avoidSuperimposedWindows = [&]
{
auto* other = windows.getUnchecked(i);
for (auto* otherWindow : windows)
{
if (otherWindow == windowToCheck)
continue;

auto b1 = mw->getBounds();
auto b2 = other->getBounds();
auto boundsToCheck = windowToCheck->getScreenBounds();
auto otherBounds = otherWindow->getScreenBounds();

if (mw != other
&& std::abs (b1.getX() - b2.getX()) < 3
&& std::abs (b1.getY() - b2.getY()) < 3
&& std::abs (b1.getRight() - b2.getRight()) < 3
&& std::abs (b1.getBottom() - b2.getBottom()) < 3)
{
int dx = 40, dy = 30;
if (std::abs (boundsToCheck.getX() - otherBounds.getX()) < 3
&& std::abs (boundsToCheck.getY() - otherBounds.getY()) < 3
&& std::abs (boundsToCheck.getRight() - otherBounds.getRight()) < 3
&& std::abs (boundsToCheck.getBottom() - otherBounds.getBottom()) < 3)
{
int dx = 40, dy = 30;

if (b1.getCentreX() >= mw->getScreenBounds().getCentreX()) dx = -dx;
if (b1.getCentreY() >= mw->getScreenBounds().getCentreY()) dy = -dy;
if (otherBounds.getCentreX() >= boundsToCheck.getCentreX()) dx = -dx;
if (otherBounds.getCentreY() >= boundsToCheck.getCentreY()) dy = -dy;

mw->setBounds (b1.translated (dx, dy));
windowToCheck->setBounds (boundsToCheck.translated (dx, dy));
}
}
}
};

auto ensureWindowIsFullyOnscreen = [&]
{
auto windowBounds = windowToCheck->getScreenBounds();
auto screenLimits = Desktop::getInstance().getDisplays().findDisplayForRect (windowBounds).userArea;

auto constrainedX = jlimit (screenLimits.getX(), screenLimits.getRight() - windowBounds.getWidth(), windowBounds.getX());
auto constrainedY = jlimit (screenLimits.getY(), screenLimits.getBottom() - windowBounds.getHeight(), windowBounds.getY());

Point<int> constrainedTopLeft (constrainedX, constrainedY);

if (windowBounds.getPosition() != constrainedTopLeft)
windowToCheck->setTopLeftPosition (constrainedTopLeft);
};

avoidSuperimposedWindows();
ensureWindowIsFullyOnscreen();
}

void MainWindowList::saveCurrentlyOpenProjectList()
Expand Down
11 changes: 6 additions & 5 deletions extras/Projucer/Source/Application/jucer_MainWindow.h
Expand Up @@ -50,14 +50,15 @@ class MainWindow : public DocumentWindow,
//==============================================================================
bool canOpenFile (const File& file) const;
bool openFile (const File& file);
void setProject (Project* newProject);
Project* getProject() const { return currentProject.get(); }

void setProject (std::unique_ptr<Project> newProject);
Project* getProject() const { return currentProject.get(); }

bool tryToOpenPIP (const File& f);

void makeVisible();
void restoreWindowPosition();
bool closeProject (Project* project, bool askToSave = true);
bool closeCurrentProject();
bool closeCurrentProject (bool askToSave);
void moveProject (File newProjectFile);

void showStartPage();
Expand Down Expand Up @@ -118,7 +119,7 @@ class MainWindowList
void reopenLastProjects();
void saveCurrentlyOpenProjectList();

void avoidSuperimposedWindows (MainWindow*);
void checkWindowBounds (MainWindow*);

void sendLookAndFeelChange();

Expand Down
Expand Up @@ -559,7 +559,7 @@ bool ProjectContentComponent::saveProject (bool shouldWait, bool openInIDE)
void ProjectContentComponent::closeProject()
{
if (auto* mw = findParentComponentOfClass<MainWindow>())
mw->closeCurrentProject();
mw->closeCurrentProject (true);
}

void ProjectContentComponent::showProjectSettings()
Expand Down
Expand Up @@ -433,7 +433,7 @@ class WizardComp : public Component,

if (project != nullptr)
{
mw->setProject (project.release());
mw->setProject (std::move (project));
getAppSettings().lastWizardFolder = projectDir.getParentDirectory();
}
}
Expand Down

0 comments on commit aeaae3b

Please sign in to comment.