diff --git a/extras/Projucer/Source/Application/StartPage/jucer_ContentComponents.h b/extras/Projucer/Source/Application/StartPage/jucer_ContentComponents.h index 97badcdd0a..766773c631 100644 --- a/extras/Projucer/Source/Application/StartPage/jucer_ContentComponents.h +++ b/extras/Projucer/Source/Application/StartPage/jucer_ContentComponents.h @@ -254,6 +254,9 @@ public: header (metadata[Ids::name].toString(), metadata[Ids::description].toString(), BinaryData::background_logo_svg), codeViewer (doc, &cppTokeniser) { + setTitle (exampleFile.getFileName()); + setFocusContainerType (FocusContainerType::focusContainer); + addAndMakeVisible (header); openExampleButton.onClick = [this] { exampleSelectedCallback (exampleFile); }; @@ -286,6 +289,7 @@ private: codeViewer.setScrollbarThickness (6); codeViewer.setReadOnly (true); + codeViewer.setTitle ("Code"); getAppSettings().appearance.applyToCodeEditor (codeViewer); codeViewer.scrollToLine (findBestLineToScrollToForClass (StringArray::fromLines (fileString), diff --git a/extras/Projucer/Source/Application/StartPage/jucer_StartPageComponent.cpp b/extras/Projucer/Source/Application/StartPage/jucer_StartPageComponent.cpp index 2d0a34c59d..3c08474b60 100644 --- a/extras/Projucer/Source/Application/StartPage/jucer_StartPageComponent.cpp +++ b/extras/Projucer/Source/Application/StartPage/jucer_StartPageComponent.cpp @@ -34,6 +34,12 @@ //============================================================================== struct ContentComponent : public Component { + ContentComponent() + { + setTitle ("Content"); + setFocusContainerType (FocusContainerType::focusContainer); + } + void resized() override { if (content != nullptr) @@ -88,7 +94,8 @@ static std::unique_ptr createExampleProjectsTab (ContentComponent& co content.setContent (std::make_unique (findExampleFile (category, index), cb)); }; - return std::make_unique (exampleCategories, + return std::make_unique ("Examples", + exampleCategories, examples, std::move (selectedCallback), StartPageTreeHolder::Open::no); @@ -144,7 +151,8 @@ static std::unique_ptr createProjectTemplatesTab (ContentComponent& c content.setContent (std::make_unique (templates[(size_t) index], std::move (cb))); }; - auto holder = std::make_unique (categories, + auto holder = std::make_unique ("Templates", + categories, templateNames, std::move (selectedCallback), StartPageTreeHolder::Open::yes); @@ -165,7 +173,14 @@ struct ProjectTemplatesAndExamples : public TabbedComponent content (c), exampleSelectedCallback (std::move (exampleCb)) { - addTab ("New Project", Colours::transparentBlack, createProjectTemplatesTab (content, std::move (newProjectCb)).release(), true); + setTitle ("Templates and Examples"); + setFocusContainerType (FocusContainerType::focusContainer); + + addTab ("New Project", + Colours::transparentBlack, + createProjectTemplatesTab (content, std::move (newProjectCb)).release(), + true); + refreshExamplesTab(); } @@ -177,8 +192,9 @@ struct ProjectTemplatesAndExamples : public TabbedComponent auto exampleTabs = createExampleProjectsTab (content, exampleSelectedCallback); - addTab ("Open Example", Colours::transparentBlack, exampleTabs == nullptr ? new SetJUCEPathComponent (*this) - : exampleTabs.release(), + addTab ("Open Example", + Colours::transparentBlack, + exampleTabs == nullptr ? new SetJUCEPathComponent (*this) : exampleTabs.release(), true); if (wasOpen) diff --git a/extras/Projucer/Source/Application/StartPage/jucer_StartPageTreeHolder.h b/extras/Projucer/Source/Application/StartPage/jucer_StartPageTreeHolder.h index 5228a566f3..4a7cd34e2c 100644 --- a/extras/Projucer/Source/Application/StartPage/jucer_StartPageTreeHolder.h +++ b/extras/Projucer/Source/Application/StartPage/jucer_StartPageTreeHolder.h @@ -31,14 +31,18 @@ class StartPageTreeHolder : public Component public: enum class Open { no, yes }; - StartPageTreeHolder (const StringArray& headerNames, const std::vector& itemNames, - std::function&& selectedCallback, Open shouldBeOpen) + StartPageTreeHolder (const String& title, + const StringArray& headerNames, + const std::vector& itemNames, + std::function&& selectedCallback, + Open shouldBeOpen) : headers (headerNames), items (itemNames), itemSelectedCallback (std::move (selectedCallback)) { jassert (headers.size() == (int) items.size()); + tree.setTitle (title); tree.setRootItem (new TreeRootItem (*this)); tree.setRootItemVisible (false); tree.setIndentSize (15); @@ -88,13 +92,14 @@ private: addSubItem (new TreeSubItem (owner, s, {})); } - bool mightContainSubItems() override { return isHeader; } - bool canBeSelected() const override { return ! isHeader; } + bool mightContainSubItems() override { return isHeader; } + bool canBeSelected() const override { return ! isHeader; } - int getItemWidth() const override { return -1; } - int getItemHeight() const override { return 25; } + int getItemWidth() const override { return -1; } + int getItemHeight() const override { return 25; } - String getUniqueName() const override { return name; } + String getUniqueName() const override { return name; } + String getAccessibilityName() override { return getUniqueName(); } void paintOpenCloseButton (Graphics& g, const Rectangle& area, Colour, bool isMouseOver) override { @@ -122,10 +127,13 @@ private: g.drawFittedText (name, bounds.reduced (5).withTrimmedLeft (10), Justification::centredLeft, 1); } - void itemClicked (const MouseEvent&) override + void itemClicked (const MouseEvent& e) override { if (isSelected()) itemSelectionChanged (true); + + if (e.mods.isPopupMenu() && mightContainSubItems()) + setOpen (! isOpen()); } void itemSelectionChanged (bool isNowSelected) override diff --git a/extras/Projucer/Source/Application/UserAccount/jucer_LoginFormComponent.h b/extras/Projucer/Source/Application/UserAccount/jucer_LoginFormComponent.h index 9d43feb13c..9d0d001ac1 100644 --- a/extras/Projucer/Source/Application/UserAccount/jucer_LoginFormComponent.h +++ b/extras/Projucer/Source/Application/UserAccount/jucer_LoginFormComponent.h @@ -35,16 +35,21 @@ public: LoginFormComponent (MainWindow& window) : mainWindow (window) { + setTitle ("Login"); + setFocusContainerType (FocusContainerType::focusContainer); + addAndMakeVisible (emailBox); emailBox.setTextToShowWhenEmpty ("Email", Colours::black.withAlpha (0.2f)); emailBox.setJustification (Justification::centredLeft); emailBox.onReturnKey = [this] { submitDetails(); }; + emailBox.setTitle ("Email"); addAndMakeVisible (passwordBox); passwordBox.setTextToShowWhenEmpty ("Password", Colours::black.withAlpha (0.2f)); passwordBox.setPasswordCharacter ((juce_wchar) 0x2022); passwordBox.setJustification (Justification::centredLeft); passwordBox.onReturnKey = [this] { submitDetails(); }; + passwordBox.setTitle ("Password"); addAndMakeVisible (logInButton); logInButton.onClick = [this] { submitDetails(); }; @@ -72,6 +77,7 @@ public: dismissButton.setShape (getLookAndFeel().getCrossShape (1.0f), false, true, false); addAndMakeVisible (dismissButton); dismissButton.onClick = [this] { mainWindow.hideLoginFormOverlay(); }; + dismissButton.setTitle ("Dismiss"); setWantsKeyboardFocus (true); setOpaque (true); diff --git a/extras/Projucer/Source/Application/Windows/jucer_GlobalPathsWindowComponent.h b/extras/Projucer/Source/Application/Windows/jucer_GlobalPathsWindowComponent.h index 74a4ef3832..e0e2dd87d6 100644 --- a/extras/Projucer/Source/Application/Windows/jucer_GlobalPathsWindowComponent.h +++ b/extras/Projucer/Source/Application/Windows/jucer_GlobalPathsWindowComponent.h @@ -127,9 +127,9 @@ public: PropertyComponent* jucePathPropertyComponent = nullptr; - for (auto* prop : propertyGroup.properties) + for (const auto& prop : propertyGroup.getProperties()) if (prop->getName() == "Path to JUCE") - jucePathPropertyComponent = prop; + jucePathPropertyComponent = prop.get(); if (jucePathPropertyComponent != nullptr) { diff --git a/extras/Projucer/Source/Application/jucer_MainWindow.cpp b/extras/Projucer/Source/Application/jucer_MainWindow.cpp index ecbd79523d..d92892ff45 100644 --- a/extras/Projucer/Source/Application/jucer_MainWindow.cpp +++ b/extras/Projucer/Source/Application/jucer_MainWindow.cpp @@ -487,6 +487,10 @@ void MainWindow::showLoginFormOverlay() { blurOverlayComponent = std::make_unique (*this, std::make_unique (*this)); loginFormOpen = true; + + if (auto* loginForm = blurOverlayComponent->getChildComponent (0)) + if (auto* handler = loginForm->getAccessibilityHandler()) + handler->grabFocus(); } void MainWindow::hideLoginFormOverlay() diff --git a/extras/Projucer/Source/CodeEditor/jucer_LiveBuildCodeEditor.h b/extras/Projucer/Source/CodeEditor/jucer_LiveBuildCodeEditor.h index c87b3e81c2..a80c6e9a67 100644 --- a/extras/Projucer/Source/CodeEditor/jucer_LiveBuildCodeEditor.h +++ b/extras/Projucer/Source/CodeEditor/jucer_LiveBuildCodeEditor.h @@ -708,17 +708,16 @@ public: } }; - Component* createEditor() override + std::unique_ptr createEditor() override { - SourceCodeEditor* e = nullptr; - - if (fileNeedsCppSyntaxHighlighting (getFile())) - e = new SourceCodeEditor (this, new LiveBuildCodeEditor (*this, getCodeDocument())); - else - e = new SourceCodeEditor (this, getCodeDocument()); + auto e = fileNeedsCppSyntaxHighlighting (getFile()) ? std::make_unique (this, new LiveBuildCodeEditor (*this, getCodeDocument())) + : std::make_unique (this, getCodeDocument()); applyLastState (*(e->editor)); - return e; + + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wredundant-move") + return std::move (e); + JUCE_END_IGNORE_WARNINGS_GCC_LIKE } // override save() to make a few more attempts at saving if it fails, since on Windows diff --git a/extras/Projucer/Source/CodeEditor/jucer_OpenDocumentManager.cpp b/extras/Projucer/Source/CodeEditor/jucer_OpenDocumentManager.cpp index 22cf720052..416b744565 100644 --- a/extras/Projucer/Source/CodeEditor/jucer_OpenDocumentManager.cpp +++ b/extras/Projucer/Source/CodeEditor/jucer_OpenDocumentManager.cpp @@ -59,8 +59,8 @@ public: void reloadFromFile() override { fileModificationTime = file.getLastModificationTime(); } String getName() const override { return file.getFileName(); } File getFile() const override { return file; } - Component* createEditor() override { return new ItemPreviewComponent (file); } - Component* createViewer() override { return createEditor(); } + std::unique_ptr createEditor() override { return std::make_unique (file); } + std::unique_ptr createViewer() override { return createEditor(); } void fileHasBeenRenamed (const File& newFile) override { file = newFile; } String getState() const override { return {}; } void restoreState (const String&) override {} diff --git a/extras/Projucer/Source/CodeEditor/jucer_OpenDocumentManager.h b/extras/Projucer/Source/CodeEditor/jucer_OpenDocumentManager.h index 42c712b709..7b56caca43 100644 --- a/extras/Projucer/Source/CodeEditor/jucer_OpenDocumentManager.h +++ b/extras/Projucer/Source/CodeEditor/jucer_OpenDocumentManager.h @@ -55,8 +55,8 @@ public: virtual bool saveAs() = 0; virtual bool hasFileBeenModifiedExternally() = 0; virtual void reloadFromFile() = 0; - virtual Component* createEditor() = 0; - virtual Component* createViewer() = 0; + virtual std::unique_ptr createEditor() = 0; + virtual std::unique_ptr createViewer() = 0; virtual void fileHasBeenRenamed (const File& newFile) = 0; virtual String getState() const = 0; virtual void restoreState (const String& state) = 0; diff --git a/extras/Projucer/Source/CodeEditor/jucer_SourceCodeEditor.cpp b/extras/Projucer/Source/CodeEditor/jucer_SourceCodeEditor.cpp index 665d037891..b15d269dc3 100644 --- a/extras/Projucer/Source/CodeEditor/jucer_SourceCodeEditor.cpp +++ b/extras/Projucer/Source/CodeEditor/jucer_SourceCodeEditor.cpp @@ -45,11 +45,14 @@ CodeDocument& SourceCodeDocument::getCodeDocument() return *codeDoc; } -Component* SourceCodeDocument::createEditor() +std::unique_ptr SourceCodeDocument::createEditor() { - auto* e = new SourceCodeEditor (this, getCodeDocument()); + auto e = std::make_unique (this, getCodeDocument()); applyLastState (*(e->editor)); - return e; + + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wredundant-move") + return std::move (e); + JUCE_END_IGNORE_WARNINGS_GCC_LIKE } void SourceCodeDocument::reloadFromFile() @@ -380,7 +383,7 @@ public: addAndMakeVisible (findNext); setWantsKeyboardFocus (false); - setFocusContainer (true); + setFocusContainerType (FocusContainerType::keyboardFocusContainer); findPrev.setWantsKeyboardFocus (false); findNext.setWantsKeyboardFocus (false); diff --git a/extras/Projucer/Source/CodeEditor/jucer_SourceCodeEditor.h b/extras/Projucer/Source/CodeEditor/jucer_SourceCodeEditor.h index c1e0ccb168..35af349ace 100644 --- a/extras/Projucer/Source/CodeEditor/jucer_SourceCodeEditor.h +++ b/extras/Projucer/Source/CodeEditor/jucer_SourceCodeEditor.h @@ -83,8 +83,8 @@ public: bool save() override; bool saveAs() override; - Component* createEditor() override; - Component* createViewer() override { return createEditor(); } + std::unique_ptr createEditor() override; + std::unique_ptr createViewer() override { return createEditor(); } void updateLastState (CodeEditorComponent&); void applyLastState (CodeEditorComponent&) const; diff --git a/extras/Projucer/Source/ComponentEditor/UI/jucer_ComponentLayoutEditor.cpp b/extras/Projucer/Source/ComponentEditor/UI/jucer_ComponentLayoutEditor.cpp index 78702c8622..292f670a43 100644 --- a/extras/Projucer/Source/ComponentEditor/UI/jucer_ComponentLayoutEditor.cpp +++ b/extras/Projucer/Source/ComponentEditor/UI/jucer_ComponentLayoutEditor.cpp @@ -41,7 +41,7 @@ public: { setInterceptsMouseClicks (false, false); setWantsKeyboardFocus (false); - setFocusContainer (true); + setFocusContainerType (FocusContainerType::keyboardFocusContainer); } void paint (Graphics& g) override @@ -254,7 +254,7 @@ void ComponentLayoutEditor::refreshAllComponents() lastComp = c; c->setWantsKeyboardFocus (false); - c->setFocusContainer (true); + c->setFocusContainerType (FocusContainerType::keyboardFocusContainer); if (isNewOverlay) overlay->updateBoundsToMatchTarget(); diff --git a/extras/Projucer/Source/ComponentEditor/jucer_JucerDocument.cpp b/extras/Projucer/Source/ComponentEditor/jucer_JucerDocument.cpp index 177028fac3..3093d404a7 100644 --- a/extras/Projucer/Source/ComponentEditor/jucer_JucerDocument.cpp +++ b/extras/Projucer/Source/ComponentEditor/jucer_JucerDocument.cpp @@ -713,14 +713,14 @@ public: return false; } - Component* createEditor() override + std::unique_ptr createEditor() override { if (ProjucerApplication::getApp().isGUIEditorEnabled()) { std::unique_ptr jucerDoc (JucerDocument::createForCppFile (getProject(), getFile())); if (jucerDoc != nullptr) - return new JucerDocumentEditor (jucerDoc.release()); + return std::make_unique (jucerDoc.release()); } return SourceCodeDocument::createEditor(); diff --git a/extras/Projucer/Source/LiveBuildEngine/UI/jucer_ComponentListComponent.h b/extras/Projucer/Source/LiveBuildEngine/UI/jucer_ComponentListComponent.h index 0b89f44763..e36288031b 100644 --- a/extras/Projucer/Source/LiveBuildEngine/UI/jucer_ComponentListComponent.h +++ b/extras/Projucer/Source/LiveBuildEngine/UI/jucer_ComponentListComponent.h @@ -158,15 +158,19 @@ private: bool mightContainSubItems() override { return false; } String getUniqueName() const override { return comp.getName(); } int getRightHandButtonSpace() override { return canBeLaunched() ? 60 : 40; } - Component* createItemComponent() override + + std::unique_ptr createItemComponent() override { - auto* content = new TreeItemComponent (*this); + auto content = std::make_unique (*this); content->addRightHandButton (new ClassItemButton (*this, true)); + if (canBeLaunched()) content->addRightHandButton (new ClassItemButton (*this, false)); - return content; + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wredundant-move") + return std::move (content); + JUCE_END_IGNORE_WARNINGS_GCC_LIKE } Colour getContentColour (bool isIcon) const override diff --git a/extras/Projucer/Source/LiveBuildEngine/UI/jucer_ErrorListComponent.h b/extras/Projucer/Source/LiveBuildEngine/UI/jucer_ErrorListComponent.h index caad6dfe1d..f290bf0d45 100644 --- a/extras/Projucer/Source/LiveBuildEngine/UI/jucer_ErrorListComponent.h +++ b/extras/Projucer/Source/LiveBuildEngine/UI/jucer_ErrorListComponent.h @@ -274,11 +274,11 @@ private: : defaultTextColourId); } - void showPopupMenu() override + void showPopupMenu (Point p) override { PopupMenu menu; menu.addItem (1, "Copy"); - launchPopupMenu (menu); + launchPopupMenu (menu, p); } void handlePopupMenuResult (int resultCode) override @@ -294,17 +294,12 @@ private: SourceCodeEditor* getEditor() { - if (ProjectContentComponent* pcc = getProjectContentComponent()) + if (auto* pcc = getProjectContentComponent()) { - const File file (File::createFileWithoutCheckingPath (message.range.file)); + const auto file = File::createFileWithoutCheckingPath (message.range.file); if (message.range.isValid() && file.exists() && pcc->showEditorForFile (file, false)) - { - if (SourceCodeEditor* ed = dynamic_cast (pcc->getEditorComponent())) - { - return ed; - } - } + return dynamic_cast (pcc->getEditorComponent()); } return nullptr; @@ -337,7 +332,7 @@ private: if (ProjectContentComponent* pcc = getProjectContentComponent()) { - if (SourceCodeEditor* ed = dynamic_cast (pcc->getEditorComponent())) + if (auto* ed = dynamic_cast (pcc->getEditorComponent())) { auto start = CodeDocument::Position (ed->editor->getDocument(), message.range.range.getStart()); auto end = CodeDocument::Position (ed->editor->getDocument(), message.range.range.getEnd()); diff --git a/extras/Projucer/Source/Project/UI/Sidebar/jucer_ExporterTreeItems.h b/extras/Projucer/Source/Project/UI/Sidebar/jucer_ExporterTreeItems.h index d9bd8eb47a..53e046b586 100644 --- a/extras/Projucer/Source/Project/UI/Sidebar/jucer_ExporterTreeItems.h +++ b/extras/Projucer/Source/Project/UI/Sidebar/jucer_ExporterTreeItems.h @@ -93,7 +93,7 @@ public: addSubItem (new ConfigItem (config.config, *exporter)); } - void showPopupMenu() override + void showPopupMenu (Point p) override { PopupMenu menu; menu.addItem (1, "Add a new configuration", exporter->supportsUserDefinedConfigurations()); @@ -101,15 +101,15 @@ public: menu.addSeparator(); menu.addItem (3, "Delete this exporter"); - launchPopupMenu (menu); + launchPopupMenu (menu, p); } - void showAddMenu() override + void showAddMenu (Point p) override { PopupMenu menu; menu.addItem (1, "Add a new configuration", exporter->supportsUserDefinedConfigurations()); - launchPopupMenu (menu); + launchPopupMenu (menu, p); } void handlePopupMenuResult (int resultCode) override @@ -239,7 +239,7 @@ public: } } - void showPopupMenu() override + void showPopupMenu (Point p) override { bool enabled = exporter.supportsUserDefinedConfigurations(); @@ -248,7 +248,7 @@ public: menu.addSeparator(); menu.addItem (2, "Delete this configuration", enabled); - launchPopupMenu (menu); + launchPopupMenu (menu, p); } void handlePopupMenuResult (int resultCode) override @@ -320,7 +320,7 @@ public: void setName (const String&) override {} Icon getIcon() const override { return project.getMainGroup().getIcon (isOpen()).withColour (getContentColour (true)); } - void showPopupMenu() override + void showPopupMenu (Point) override { if (auto* pcc = getProjectContentComponent()) pcc->showNewExporterMenu(); diff --git a/extras/Projucer/Source/Project/UI/Sidebar/jucer_FileTreeItems.h b/extras/Projucer/Source/Project/UI/Sidebar/jucer_FileTreeItems.h index 8604d17d62..cb4a0dac64 100644 --- a/extras/Projucer/Source/Project/UI/Sidebar/jucer_FileTreeItems.h +++ b/extras/Projucer/Source/Project/UI/Sidebar/jucer_FileTreeItems.h @@ -131,7 +131,7 @@ public: { if (auto* pcc = treeRootItem->getProjectContentComponent()) { - if (auto* fileInfoComp = dynamic_cast (pcc->getEditorComponentContent())) + if (auto* fileInfoComp = dynamic_cast (pcc->getEditorComponent())) if (fileInfoComp->getGroupPath() == itemToRemove->getFile().getFullPathName()) pcc->hideEditor(); } @@ -197,12 +197,12 @@ public: jassertfalse; } - void showMultiSelectionPopupMenu() override + void showMultiSelectionPopupMenu (Point p) override { PopupMenu m; m.addItem (1, "Delete"); - m.showMenuAsync (PopupMenu::Options(), + m.showMenuAsync (PopupMenu::Options().withTargetScreenArea ({ p.x, p.y, 1, 1 }), ModalCallbackFunction::create (treeViewMultiSelectItemChosen, this)); } @@ -548,7 +548,7 @@ public: pcc->showEditorForFile (f, false); } - void showPopupMenu() override + void showPopupMenu (Point p) override { PopupMenu m; @@ -571,13 +571,13 @@ public: m.addItem (3, "Delete"); - launchPopupMenu (m); + launchPopupMenu (m, p); } - void showAddMenu() override + void showAddMenu (Point p) override { if (auto* group = dynamic_cast (getParentItem())) - group->showAddMenu(); + group->showAddMenu (p); } void handlePopupMenuResult (int resultCode) override @@ -696,7 +696,7 @@ public: void showDocument() override { if (auto* pcc = getProjectContentComponent()) - pcc->setEditorComponent (new FileGroupInformationComponent (item), nullptr); + pcc->setScrollableEditorComponent (std::make_unique (item)); } static void openAllGroups (TreeViewItem* root) @@ -731,7 +731,7 @@ public: setFilesToCompile (projectItem.getChild (i), shouldCompile); } - void showPopupMenu() override + void showPopupMenu (Point p) override { PopupMenu m; addCreateFileMenuItems (m); @@ -764,15 +764,15 @@ public: m.addItem (10, "Delete"); } - launchPopupMenu (m); + launchPopupMenu (m, p); } - void showAddMenu() override + void showAddMenu (Point p) override { PopupMenu m; addCreateFileMenuItems (m); - launchPopupMenu (m); + launchPopupMenu (m, p); } void handlePopupMenuResult (int resultCode) override diff --git a/extras/Projucer/Source/Project/UI/Sidebar/jucer_ModuleTreeItems.h b/extras/Projucer/Source/Project/UI/Sidebar/jucer_ModuleTreeItems.h index 891c27bcc9..f2aec1a3b3 100644 --- a/extras/Projucer/Source/Project/UI/Sidebar/jucer_ModuleTreeItems.h +++ b/extras/Projucer/Source/Project/UI/Sidebar/jucer_ModuleTreeItems.h @@ -78,17 +78,17 @@ public: return Icon (getIcons().singleModule, iconColour); } - void showAddMenu() override + void showAddMenu (Point p) override { if (auto* parent = dynamic_cast (getParentItem())) - parent->showPopupMenu(); + parent->showPopupMenu (p); } - void showPopupMenu() override + void showPopupMenu (Point p) override { PopupMenu menu; menu.addItem (1, "Remove this module"); - launchPopupMenu (menu); + launchPopupMenu (menu, p); } void handlePopupMenuResult (int resultCode) override @@ -149,7 +149,7 @@ private: if (modules.doesModuleHaveHigherCppStandardThanProject (moduleID)) props.add (new CppStandardWarningComponent()); - group.properties.clear(); + group.clearProperties(); exporterModulePathDefaultValues.clear(); exporterModulePathValues.clear(); globalPathValues.clear(); @@ -471,7 +471,7 @@ public: void showDocument() override { if (auto* pcc = getProjectContentComponent()) - pcc->setEditorComponent (new ModulesInformationComponent (project), nullptr); + pcc->setScrollableEditorComponent (std::make_unique (project)); } static File getModuleFolder (const File& draggedFile) @@ -515,7 +515,7 @@ public: addSubItem (new ModuleItem (project, project.getEnabledModules().getModuleID (i))); } - void showPopupMenu() override + void showPopupMenu (Point p) override { auto& enabledModules = project.getEnabledModules(); PopupMenu allModules; @@ -563,7 +563,7 @@ public: menu.addSeparator(); menu.addItem (1001, "Add a module from a specified folder..."); - launchPopupMenu (menu); + launchPopupMenu (menu, p); } void handlePopupMenuResult (int resultCode) override diff --git a/extras/Projucer/Source/Project/UI/Sidebar/jucer_ProjectTab.h b/extras/Projucer/Source/Project/UI/Sidebar/jucer_ProjectTab.h index 631dbc719a..2aaba9c6d7 100644 --- a/extras/Projucer/Source/Project/UI/Sidebar/jucer_ProjectTab.h +++ b/extras/Projucer/Source/Project/UI/Sidebar/jucer_ProjectTab.h @@ -35,6 +35,9 @@ struct ProjectSettingsComponent : public Component, group (project.getProjectFilenameRootString(), Icon (getIcons().settings, Colours::transparentBlack)) { + setTitle ("Project Settings"); + setFocusContainerType (FocusContainerType::focusContainer); + addAndMakeVisible (group); updatePropertyList(); @@ -238,16 +241,34 @@ private: headers.clear(); - if (project != nullptr) + auto addPanel = [this] (const String& name, + TreePanelBase* tree, + ConcertinaTreeComponent::AdditionalComponents components, + const Path& icon) { - concertinaPanel.addPanel (0, new ConcertinaTreeComponent (new FileTreePanel (*project), true, false, true), true); - concertinaPanel.addPanel (1, new ConcertinaTreeComponent (new ModuleTreePanel (*project), true, true), true); - concertinaPanel.addPanel (2, new ConcertinaTreeComponent (new ExportersTreePanel (*project), true), true); - } + if (project != nullptr) + concertinaPanel.addPanel (-1, new ConcertinaTreeComponent (name, tree, components), true); + + headers.add (new ConcertinaHeader (name, icon)); + }; + + using AdditionalComponents = ConcertinaTreeComponent::AdditionalComponents; + + addPanel ("File Explorer", new FileTreePanel (*project), + AdditionalComponents{} + .with (AdditionalComponents::addButton) + .with (AdditionalComponents::findPanel), + getIcons().fileExplorer); + + addPanel ("Modules", new ModuleTreePanel (*project), + AdditionalComponents{} + .with (AdditionalComponents::addButton) + .with (AdditionalComponents::settingsButton), + getIcons().modules); - headers.add (new ConcertinaHeader ("File explorer", getIcons().fileExplorer)); - headers.add (new ConcertinaHeader ("Modules", getIcons().modules)); - headers.add (new ConcertinaHeader ("Exporters", getIcons().exporter)); + addPanel ("Exporters", new ExportersTreePanel (*project), + AdditionalComponents{}.with (AdditionalComponents::addButton), + getIcons().exporter); for (int i = 0; i < concertinaPanel.getNumPanels(); ++i) { diff --git a/extras/Projucer/Source/Project/UI/Sidebar/jucer_ProjectTreeItemBase.h b/extras/Projucer/Source/Project/UI/Sidebar/jucer_ProjectTreeItemBase.h index 1443832be2..fd57ac41da 100644 --- a/extras/Projucer/Source/Project/UI/Sidebar/jucer_ProjectTreeItemBase.h +++ b/extras/Projucer/Source/Project/UI/Sidebar/jucer_ProjectTreeItemBase.h @@ -35,17 +35,16 @@ struct ProjectTreeItemBase : public JucerTreeViewBase, void showSettingsPage (Component* content) { content->setComponentID (getUniqueName()); - std::unique_ptr comp (content); - if (ProjectContentComponent* pcc = getProjectContentComponent()) - pcc->setEditorComponent (comp.release(), nullptr); + if (auto* pcc = getProjectContentComponent()) + pcc->setScrollableEditorComponent (std::move (comp)); } void closeSettingsPage() { if (auto* pcc = getProjectContentComponent()) - if (auto* content = pcc->getEditorComponentContent()) + if (auto* content = pcc->getEditorComponent()) if (content->getComponentID() == getUniqueName()) pcc->hideEditor(); } diff --git a/extras/Projucer/Source/Project/UI/Sidebar/jucer_TabComponents.h b/extras/Projucer/Source/Project/UI/Sidebar/jucer_TabComponents.h index 8027225cfb..fba0c155dd 100644 --- a/extras/Projucer/Source/Project/UI/Sidebar/jucer_TabComponents.h +++ b/extras/Projucer/Source/Project/UI/Sidebar/jucer_TabComponents.h @@ -34,11 +34,14 @@ public: ConcertinaHeader (String n, Path p) : Component (n), name (n), iconPath (p) { + setTitle (getName()); + panelIcon = Icon (iconPath, Colours::white); nameLabel.setText (name, dontSendNotification); nameLabel.setJustificationType (Justification::centredLeft); nameLabel.setInterceptsMouseClicks (false, false); + nameLabel.setAccessible (false); nameLabel.setColour (Label::textColourId, Colours::white); addAndMakeVisible (nameLabel); @@ -72,6 +75,14 @@ public: sendChangeMessage(); } + std::unique_ptr createAccessibilityHandler() override + { + return std::make_unique (*this, + AccessibilityRole::button, + AccessibilityActions().addAction (AccessibilityActionType::press, + [this] { sendChangeMessage(); })); + } + int direction = 0; int yPosition = 0; @@ -166,25 +177,57 @@ private: class ConcertinaTreeComponent : public Component { public: - ConcertinaTreeComponent (TreePanelBase* tree, bool hasAddButton = false, - bool hasSettingsButton = false, bool hasFindPanel = false) - : treeToDisplay (tree) + class AdditionalComponents { - if (hasAddButton) + public: + enum Type + { + addButton = (1 << 0), + settingsButton = (1 << 1), + findPanel = (1 << 2) + }; + + AdditionalComponents with (Type t) + { + auto copy = *this; + copy.componentTypes |= t; + + return copy; + } + + bool has (Type t) const noexcept + { + return (componentTypes & t) != 0; + } + + private: + int componentTypes = 0; + }; + + ConcertinaTreeComponent (const String& name, + TreePanelBase* tree, + AdditionalComponents additionalComponents) + : Component (name), + treeToDisplay (tree) + { + setTitle (getName()); + setFocusContainerType (FocusContainerType::focusContainer); + + if (additionalComponents.has (AdditionalComponents::addButton)) { addButton = std::make_unique ("Add", getIcons().plus); addAndMakeVisible (addButton.get()); addButton->onClick = [this] { showAddMenu(); }; } - if (hasSettingsButton) + if (additionalComponents.has (AdditionalComponents::settingsButton)) { settingsButton = std::make_unique ("Settings", getIcons().settings); addAndMakeVisible (settingsButton.get()); settingsButton->onClick = [this] { showSettings(); }; } - if (hasFindPanel) + if (additionalComponents.has (AdditionalComponents::findPanel)) { findPanel = std::make_unique ([this] (const String& filter) { treeToDisplay->rootItem->setSearchFilter (filter); }); addAndMakeVisible (findPanel.get()); @@ -232,12 +275,12 @@ private: if (numSelected == 0) { if (auto* root = dynamic_cast (treeToDisplay->tree.getRootItem())) - root->showPopupMenu(); + root->showPopupMenu (addButton->getScreenBounds().getCentre()); } else { if (auto* item = dynamic_cast (treeToDisplay->tree.getSelectedItem (0))) - item->showAddMenu(); + item->showAddMenu (addButton->getScreenBounds().getCentre()); } } diff --git a/extras/Projucer/Source/Project/UI/jucer_ContentViewComponent.h b/extras/Projucer/Source/Project/UI/jucer_ContentViewComponent.h new file mode 100644 index 0000000000..39f933070e --- /dev/null +++ b/extras/Projucer/Source/Project/UI/jucer_ContentViewComponent.h @@ -0,0 +1,112 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2020 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + By using JUCE, you agree to the terms of both the JUCE 6 End-User License + Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020). + + End User License Agreement: www.juce.com/juce-6-licence + Privacy Policy: www.juce.com/juce-privacy-policy + + Or: You may also use this code under the terms of the GPL v3 (see + www.gnu.org/licenses). + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +#pragma once + + +//============================================================================== +class ContentViewComponent : public Component +{ +public: + ContentViewComponent() + { + setTitle ("Content"); + setFocusContainerType (Component::FocusContainerType::focusContainer); + + addAndMakeVisible (logoComponent); + + addAndMakeVisible (fileNameLabel); + fileNameLabel.setJustificationType (Justification::centred); + } + + void resized() override + { + auto bounds = getLocalBounds(); + + fileNameLabel.setBounds (bounds.removeFromTop (15)); + + if (content != nullptr) + content->setBounds (bounds); + else + logoComponent.setBounds (bounds); + } + + Component* getCurrentComponent() noexcept + { + return content.get(); + } + + void setContent (std::unique_ptr newContent, + const String& labelText) + { + content = std::move (newContent); + addAndMakeVisible (content.get()); + + fileNameLabel.setVisible (labelText.isNotEmpty()); + fileNameLabel.setText (labelText, dontSendNotification); + + resized(); + } + +private: + class LogoComponent : public Component + { + public: + void paint (Graphics& g) override + { + g.setColour (findColour (defaultTextColourId)); + + auto bounds = getLocalBounds(); + bounds.reduce (bounds.getWidth() / 6, bounds.getHeight() / 6); + + g.setFont (15.0f); + g.drawFittedText (versionInfo, bounds.removeFromBottom (50), Justification::centredBottom, 3); + + if (logo != nullptr) + logo->drawWithin (g, bounds.withTrimmedBottom (bounds.getHeight() / 4).toFloat(), + RectanglePlacement (RectanglePlacement::centred), 1.0f); + } + + private: + std::unique_ptr logo = []() -> std::unique_ptr + { + if (auto svg = parseXML (BinaryData::background_logo_svg)) + return Drawable::createFromSVG (*svg); + + jassertfalse; + return {}; + }(); + + String versionInfo = SystemStats::getJUCEVersion() + + newLine + + ProjucerApplication::getApp().getVersionDescription(); + }; + + std::unique_ptr content; + LogoComponent logoComponent; + Label fileNameLabel; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ContentViewComponent) +}; diff --git a/extras/Projucer/Source/Project/UI/jucer_ContentViewComponents.h b/extras/Projucer/Source/Project/UI/jucer_ContentViewComponents.h index 59216320f6..ab970eac39 100644 --- a/extras/Projucer/Source/Project/UI/jucer_ContentViewComponents.h +++ b/extras/Projucer/Source/Project/UI/jucer_ContentViewComponents.h @@ -25,6 +25,7 @@ #pragma once +#include "../../Utility/UI/PropertyComponents/jucer_LabelPropertyComponent.h" //============================================================================== struct ContentViewHeader : public Component @@ -32,6 +33,7 @@ struct ContentViewHeader : public Component ContentViewHeader (String headerName, Icon headerIcon) : name (headerName), icon (headerIcon) { + setTitle (name); } void paint (Graphics& g) override @@ -152,14 +154,18 @@ private: }; //============================================================================== -class InfoButton : public Button +class InfoButton : public Button { public: InfoButton (const String& infoToDisplay = {}) : Button ({}) { + setTitle ("Info"); + if (infoToDisplay.isNotEmpty()) setInfoToDisplay (infoToDisplay); + + setSize (20, 20); } void paintButton (Graphics& g, bool isMouseOverButton, bool isButtonDown) override @@ -196,6 +202,8 @@ public: width = jmin (300, stringWidth); numLines += static_cast (stringWidth / width); + + setHelpText (info); } } @@ -242,37 +250,48 @@ public: description (desc) { addAndMakeVisible (header); - - description.setFont ({ 16.0f }); - description.setColour (getLookAndFeel().findColour (defaultTextColourId)); - description.setLineSpacing (5.0f); - description.setJustification (Justification::centredLeft); } void setProperties (const PropertyListBuilder& newProps) { - infoButtons.clear(); - properties.clear(); - properties.addArray (newProps.components); + clearProperties(); - for (auto* prop : properties) + if (description.isNotEmpty()) + properties.push_back (std::make_unique (description, 16, Font (16.0f), + Justification::centredLeft)); + + for (auto* comp : newProps.components) + properties.push_back (std::unique_ptr (comp)); + + for (auto& prop : properties) { - addAndMakeVisible (prop); + const auto propertyTooltip = prop->getTooltip(); + + if (propertyTooltip.isNotEmpty()) + { + // set the tooltip to empty so it only displays when its button is clicked + prop->setTooltip ({}); + + auto infoButton = std::make_unique (propertyTooltip); + infoButton->setAssociatedComponent (prop.get()); - if (! prop->getTooltip().isEmpty()) + auto propertyAndInfoWrapper = std::make_unique (*prop, *infoButton.get()); + addAndMakeVisible (propertyAndInfoWrapper.get()); + propertyComponentsWithInfo.push_back (std::move (propertyAndInfoWrapper)); + + infoButtons.push_back (std::move (infoButton)); + } + else { - addAndMakeVisible (infoButtons.add (new InfoButton (prop->getTooltip()))); - infoButtons.getLast()->setAssociatedComponent (prop); - prop->setTooltip ({}); // set the tooltip to empty so it only displays when its button is clicked + addAndMakeVisible (prop.get()); } - if (auto* multiChoice = dynamic_cast (prop)) + if (auto* multiChoice = dynamic_cast (prop.get())) multiChoice->onHeightChange = [this] { updateSize(); }; - if (auto* text = dynamic_cast (prop)) + if (auto* text = dynamic_cast (prop.get())) if (text->isTextEditorMultiLine()) text->addListener (this); - } } @@ -281,31 +300,21 @@ public: header.setBounds (0, 0, width, headerSize); auto height = header.getBottom() + 10; - descriptionLayout.createLayout (description, (float) (width - 40)); - auto descriptionHeight = (int) descriptionLayout.getHeight(); - - if (descriptionHeight > 0) - height += (int) descriptionLayout.getHeight() + 25; - - for (auto* pp : properties) + for (auto& pp : properties) { - auto propertyHeight = pp->getPreferredHeight() + (getHeightMultiplier (pp) * pp->getPreferredHeight()); + const auto propertyHeight = pp->getPreferredHeight() + + (getHeightMultiplier (pp.get()) * pp->getPreferredHeight()); - InfoButton* buttonToUse = nullptr; - for (auto* b : infoButtons) - if (b->getAssociatedComponent() == pp) - buttonToUse = b; + auto iter = std::find_if (propertyComponentsWithInfo.begin(), propertyComponentsWithInfo.end(), + [&pp] (const std::unique_ptr& w) { return &w->propertyComponent == pp.get(); }); - if (buttonToUse != nullptr) - { - buttonToUse->setSize (20, 20); - buttonToUse->setCentrePosition (20, height + (propertyHeight / 2)); - } - - pp->setBounds (40, height, width - 50, propertyHeight); + if (iter != propertyComponentsWithInfo.end()) + (*iter)->setBounds (0, height, width - 10, propertyHeight); + else + pp->setBounds (40, height, width - 50, propertyHeight); - if (shouldResizePropertyComponent (pp)) - resizePropertyComponent (pp); + if (shouldResizePropertyComponent (pp.get())) + resizePropertyComponent (pp.get()); height += pp->getHeight() + 10; } @@ -319,19 +328,51 @@ public: void paint (Graphics& g) override { - g.setColour (findColour (secondaryBackgroundColourId)); - g.fillRect (getLocalBounds()); - - auto textArea = getLocalBounds().toFloat() - .withTop ((float) headerSize) - .reduced (20.0f, 10.0f) - .withHeight (descriptionLayout.getHeight()); - descriptionLayout.draw (g, textArea); + g.fillAll (findColour (secondaryBackgroundColourId)); + } + + const std::vector>& getProperties() const noexcept + { + return properties; } - OwnedArray properties; + void clearProperties() + { + propertyComponentsWithInfo.clear(); + infoButtons.clear(); + properties.clear(); + } private: + //============================================================================== + struct PropertyAndInfoWrapper : public Component + { + PropertyAndInfoWrapper (PropertyComponent& c, InfoButton& i) + : propertyComponent (c), + infoButton (i) + { + setFocusContainerType (FocusContainerType::focusContainer); + setTitle (propertyComponent.getName()); + + addAndMakeVisible (propertyComponent); + addAndMakeVisible (infoButton); + } + + void resized() override + { + auto bounds = getLocalBounds(); + + bounds.removeFromLeft (40); + bounds.removeFromRight (10); + + propertyComponent.setBounds (bounds); + infoButton.setCentrePosition (20, bounds.getHeight() / 2); + } + + PropertyComponent& propertyComponent; + InfoButton& infoButton; + }; + //============================================================================== void textPropertyComponentChanged (TextPropertyComponent* comp) override { @@ -348,7 +389,6 @@ private: updateSize(); } - //============================================================================== void updateSize() { updateSize (getX(), getY(), getWidth()); @@ -357,7 +397,6 @@ private: parent->parentSizeChanged(); } - //============================================================================== bool shouldResizePropertyComponent (PropertyComponent* p) { if (auto* textComp = dynamic_cast (p)) @@ -392,11 +431,15 @@ private: return static_cast (nameWidth / (float) availableTextWidth); } - OwnedArray infoButtons; + //============================================================================== + static constexpr int headerSize = 40; + + std::vector> properties; + std::vector> infoButtons; + std::vector> propertyComponentsWithInfo; + ContentViewHeader header; - AttributedString description; - TextLayout descriptionLayout; - int headerSize = 40; + String description; //============================================================================== JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PropertyGroupComponent) diff --git a/extras/Projucer/Source/Project/UI/jucer_HeaderComponent.cpp b/extras/Projucer/Source/Project/UI/jucer_HeaderComponent.cpp index bd5a1eb93a..7223aee3e0 100644 --- a/extras/Projucer/Source/Project/UI/jucer_HeaderComponent.cpp +++ b/extras/Projucer/Source/Project/UI/jucer_HeaderComponent.cpp @@ -40,6 +40,9 @@ HeaderComponent::HeaderComponent (ProjectContentComponent* pcc) : projectContentComponent (pcc) { + setTitle ("Header"); + setFocusContainerType (FocusContainerType::focusContainer); + addAndMakeVisible (configLabel); addAndMakeVisible (exporterBox); diff --git a/extras/Projucer/Source/Project/UI/jucer_ProjectContentComponent.cpp b/extras/Projucer/Source/Project/UI/jucer_ProjectContentComponent.cpp index 63c5dce263..ddbc17720b 100644 --- a/extras/Projucer/Source/Project/UI/jucer_ProjectContentComponent.cpp +++ b/extras/Projucer/Source/Project/UI/jucer_ProjectContentComponent.cpp @@ -34,63 +34,23 @@ NewFileWizard::Type* createGUIComponentWizard(); -//============================================================================== -ProjectContentComponent::LogoComponent::LogoComponent() -{ - if (auto svg = parseXML (BinaryData::background_logo_svg)) - logo = Drawable::createFromSVG (*svg); -} - -void ProjectContentComponent::LogoComponent::paint (Graphics& g) -{ - g.setColour (findColour (defaultTextColourId)); - - auto r = getLocalBounds(); - - g.setFont (15.0f); - g.drawFittedText (getVersionInfo(), r.removeFromBottom (50), Justification::centredBottom, 3); - - logo->drawWithin (g, r.withTrimmedBottom (r.getHeight() / 4).toFloat(), - RectanglePlacement (RectanglePlacement::centred), 1.0f); -} - -String ProjectContentComponent::LogoComponent::getVersionInfo() -{ - return SystemStats::getJUCEVersion() - + newLine - + ProjucerApplication::getApp().getVersionDescription(); -} - -//============================================================================== -ProjectContentComponent::ContentViewport::ContentViewport (Component* content) -{ - addAndMakeVisible (viewport); - viewport.setViewedComponent (content, true); -} - -void ProjectContentComponent::ContentViewport::resized() -{ - viewport.setBounds (getLocalBounds()); -} - //============================================================================== ProjectContentComponent::ProjectContentComponent() { setOpaque (true); setWantsKeyboardFocus (true); - addAndMakeVisible (logoComponent); addAndMakeVisible (headerComponent); addAndMakeVisible (projectMessagesComponent); - - addAndMakeVisible (fileNameLabel); - fileNameLabel.setJustificationType (Justification::centred); + addAndMakeVisible (contentViewComponent); sidebarSizeConstrainer.setMinimumWidth (200); sidebarSizeConstrainer.setMaximumWidth (500); sidebarTabs.setOutline (0); sidebarTabs.getTabbedButtonBar().setMinimumTabScaleFactor (0.5); + sidebarTabs.setTitle ("Sidebar"); + sidebarTabs.setFocusContainerType (FocusContainerType::focusContainer); ProjucerApplication::getApp().openDocumentManager.addListener (this); @@ -140,15 +100,9 @@ void ProjectContentComponent::resized() if (resizerBar != nullptr) resizerBar->setBounds (r.withWidth (4)); - headerComponent.sidebarTabsWidthChanged (sidebarTabs.getWidth()); - - if (contentView != nullptr) - { - fileNameLabel.setBounds (r.removeFromTop (15)); - contentView->setBounds (r); - } + contentViewComponent.setBounds (r); - logoComponent.setBounds (r.reduced (r.getWidth() / 6, r.getHeight() / 6)); + headerComponent.sidebarTabsWidthChanged (sidebarTabs.getWidth()); } void ProjectContentComponent::lookAndFeelChanged() @@ -175,8 +129,8 @@ void ProjectContentComponent::setProject (Project* newProject) if (project != nullptr) project->removeChangeListener (this); - contentView.reset(); - resizerBar.reset(); + hideEditor(); + resizerBar = nullptr; deleteProjectTabs(); project = newProject; @@ -360,16 +314,12 @@ void ProjectContentComponent::updateMissingFileStatuses() tree->updateMissingFileStatuses(); } -bool ProjectContentComponent::showEditorForFile (const File& f, bool grabFocus) +bool ProjectContentComponent::showEditorForFile (const File& fileToShow, bool grabFocus) { - if (getCurrentFile() == f - || showDocument (ProjucerApplication::getApp().openDocumentManager.openFile (project, f), grabFocus)) - { - fileNameLabel.setText (f.getFileName(), dontSendNotification); - return true; - } + if (getCurrentFile() != fileToShow) + return showDocument (ProjucerApplication::getApp().openDocumentManager.openFile (project, fileToShow), grabFocus); - return false; + return true; } bool ProjectContentComponent::hasFileInRecentList (const File& f) const @@ -391,30 +341,22 @@ bool ProjectContentComponent::showDocument (OpenDocumentManager::Document* doc, if (doc->hasFileBeenModifiedExternally()) doc->reloadFromFile(); - if (doc == getCurrentDocument() && contentView != nullptr) + if (doc != getCurrentDocument()) { - if (grabFocus) - contentView->grabKeyboardFocus(); - - return true; + recentDocumentList.newDocumentOpened (doc); + setEditorDocument (doc->createEditor(), doc); } - recentDocumentList.newDocumentOpened (doc); - - auto opened = setEditorComponent (doc->createEditor(), doc); - - if (opened && grabFocus && isShowing()) - contentView->grabKeyboardFocus(); + if (grabFocus) + contentViewComponent.grabKeyboardFocus(); - return opened; + return true; } void ProjectContentComponent::hideEditor() { currentDocument = nullptr; - contentView.reset(); - - fileNameLabel.setVisible (false); + contentViewComponent.setContent ({}, {}); ProjucerApplication::getCommandManager().commandStatusChanged(); resized(); @@ -422,68 +364,69 @@ void ProjectContentComponent::hideEditor() void ProjectContentComponent::hideDocument (OpenDocumentManager::Document* doc) { - if (doc == currentDocument) - { - if (auto* replacement = recentDocumentList.getClosestPreviousDocOtherThan (doc)) - showDocument (replacement, true); - else - hideEditor(); - } + if (doc != currentDocument) + return; + + if (auto* replacement = recentDocumentList.getClosestPreviousDocOtherThan (currentDocument)) + showDocument (replacement, true); + else + hideEditor(); } -bool ProjectContentComponent::setEditorComponent (Component* editor, - OpenDocumentManager::Document* doc) +void ProjectContentComponent::setScrollableEditorComponent (std::unique_ptr component) { - if (editor != nullptr) - { - contentView.reset(); + jassert (component.get() != nullptr); - if (doc == nullptr) + class ContentViewport : public Component + { + public: + ContentViewport (std::unique_ptr content) { - auto* viewport = new ContentViewport (editor); - - contentView.reset (viewport); - currentDocument = nullptr; - fileNameLabel.setVisible (false); - - addAndMakeVisible (viewport); + contentViewport.setViewedComponent (content.release(), true); + addAndMakeVisible (contentViewport); } - else - { - contentView.reset (editor); - currentDocument = doc; - fileNameLabel.setText (doc->getFile().getFileName(), dontSendNotification); - fileNameLabel.setVisible (true); - addAndMakeVisible (editor); + void resized() override + { + contentViewport.setBounds (getLocalBounds()); } - resized(); + private: + Viewport contentViewport; + }; - ProjucerApplication::getCommandManager().commandStatusChanged(); - return true; - } + contentViewComponent.setContent (std::make_unique (std::move (component)), {}); + currentDocument = nullptr; - return false; + ProjucerApplication::getCommandManager().commandStatusChanged(); } -Component* ProjectContentComponent::getEditorComponentContent() const +void ProjectContentComponent::setEditorDocument (std::unique_ptr component, OpenDocumentManager::Document* doc) { - if (contentView != nullptr) - if (auto* vp = dynamic_cast (contentView.get())) - return vp->viewport.getViewedComponent(); + currentDocument = doc; + contentViewComponent.setContent (std::move (component), + currentDocument != nullptr ? currentDocument->getFile().getFileName() + : String()); - return nullptr; + ProjucerApplication::getCommandManager().commandStatusChanged(); +} + +Component* ProjectContentComponent::getEditorComponent() +{ + return contentViewComponent.getCurrentComponent(); } void ProjectContentComponent::closeDocument() { if (currentDocument != nullptr) + { ProjucerApplication::getApp().openDocumentManager .closeDocument (currentDocument, OpenDocumentManager::SaveIfNeeded::yes); - else if (contentView != nullptr) - if (! goToPreviousFile()) - hideEditor(); + return; + } + + if (! goToPreviousFile()) + hideEditor(); } static void showSaveWarning (OpenDocumentManager::Document* currentDocument) @@ -570,7 +513,7 @@ void ProjectContentComponent::closeProject() void ProjectContentComponent::showProjectSettings() { - setEditorComponent (new ProjectSettingsComponent (*project), nullptr); + setScrollableEditorComponent (std::make_unique (*project)); } void ProjectContentComponent::showCurrentExporterSettings() @@ -634,7 +577,7 @@ void ProjectContentComponent::showModule (const String& moduleID) void ProjectContentComponent::showLiveBuildSettings() { - setEditorComponent (new LiveBuildSettingsComponent (*project), nullptr); + setScrollableEditorComponent (std::make_unique (*project)); } StringArray ProjectContentComponent::getExportersWhichCanLaunch() const @@ -851,7 +794,7 @@ void ProjectContentComponent::getCommandInfo (const CommandID commandID, Applica result.setInfo ("Close" + documentName, "Closes the current document", CommandCategories::general, 0); - result.setActive (contentView != nullptr); + result.setActive (currentDocument != nullptr); result.defaultKeypresses.add ({ 'w', cmdCtrl, 0 }); break; diff --git a/extras/Projucer/Source/Project/UI/jucer_ProjectContentComponent.h b/extras/Projucer/Source/Project/UI/jucer_ProjectContentComponent.h index 1654df2bed..0628d3a962 100644 --- a/extras/Projucer/Source/Project/UI/jucer_ProjectContentComponent.h +++ b/extras/Projucer/Source/Project/UI/jucer_ProjectContentComponent.h @@ -28,6 +28,7 @@ #include "../../CodeEditor/jucer_OpenDocumentManager.h" #include "jucer_HeaderComponent.h" #include "jucer_ProjectMessagesComponent.h" +#include "jucer_ContentViewComponent.h" class CompileEngineChildProcess; class ProjectTab; @@ -65,10 +66,11 @@ public: void saveAs(); void hideEditor(); - bool setEditorComponent (Component* editor, OpenDocumentManager::Document* doc); - Component* getEditorComponentContent() const; - Component* getEditorComponent() const { return contentView.get(); } - Component& getSidebarComponent() { return sidebarTabs; } + void setScrollableEditorComponent (std::unique_ptr component); + void setEditorDocument (std::unique_ptr component, OpenDocumentManager::Document* doc); + Component* getEditorComponent(); + + Component& getSidebarComponent() { return sidebarTabs; } bool goToPreviousFile(); bool goToNextFile(); @@ -144,26 +146,6 @@ public: static String getBuildTabName() { return "Build"; } private: - //============================================================================== - struct LogoComponent : public Component - { - LogoComponent(); - void paint (Graphics& g) override; - static String getVersionInfo(); - - std::unique_ptr logo; - }; - - struct ContentViewport : public Component - { - ContentViewport (Component* content); - void resized() override; - - Viewport viewport; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ContentViewport) - }; - //============================================================================== bool documentAboutToClose (OpenDocumentManager::Document*) override; void changeListenerCallback (ChangeBroadcaster*) override; @@ -196,14 +178,14 @@ private: OpenDocumentManager::Document* currentDocument = nullptr; RecentDocumentList recentDocumentList; - LogoComponent logoComponent; HeaderComponent headerComponent { this }; + TabbedComponent sidebarTabs { TabbedButtonBar::TabsAtTop }; ProjectMessagesComponent projectMessagesComponent; - Label fileNameLabel; - TabbedComponent sidebarTabs { TabbedButtonBar::TabsAtTop }; + ContentViewComponent contentViewComponent; + std::unique_ptr resizerBar; ComponentBoundsConstrainer sidebarSizeConstrainer; - std::unique_ptr translationTool, contentView; + std::unique_ptr translationTool; BubbleMessageComponent bubbleMessage; ReferenceCountedObjectPtr childProcess; diff --git a/extras/Projucer/Source/Project/UI/jucer_ProjectMessagesComponent.h b/extras/Projucer/Source/Project/UI/jucer_ProjectMessagesComponent.h index b8dc861bfc..2426951506 100644 --- a/extras/Projucer/Source/Project/UI/jucer_ProjectMessagesComponent.h +++ b/extras/Projucer/Source/Project/UI/jucer_ProjectMessagesComponent.h @@ -392,6 +392,9 @@ class ProjectMessagesComponent : public Component public: ProjectMessagesComponent() { + setFocusContainerType (FocusContainerType::focusContainer); + setTitle ("Project Messages"); + addAndMakeVisible (warningsComponent); addAndMakeVisible (notificationsComponent); @@ -445,8 +448,15 @@ public: isMouseDown = false; repaint(); - if (messagesWindow != nullptr) - showOrHideAllMessages (! messagesWindow->isListShowing()); + showOrHideMessagesWindow(); + } + + std::unique_ptr createAccessibilityHandler() override + { + return std::make_unique (*this, + AccessibilityRole::button, + AccessibilityActions().addAction (AccessibilityActionType::press, + [this] { showOrHideMessagesWindow(); })); } //============================================================================== @@ -475,6 +485,20 @@ public: } } + void numMessagesChanged() + { + const auto total = warningsComponent.getNumMessages() + + notificationsComponent.getNumMessages(); + + setHelpText (String (total) + (total == 1 ? " message" : " messages")); + } + + void showOrHideMessagesWindow() + { + if (messagesWindow != nullptr) + showOrHideAllMessages (! messagesWindow->isListShowing()); + } + private: //============================================================================== struct MessageCountComponent : public Component, @@ -511,9 +535,12 @@ private: void updateNumMessages() { numMessages = messagesTree.getNumChildren(); + owner.numMessagesChanged(); repaint(); } + int getNumMessages() const noexcept { return numMessages; } + private: void valueTreeChildAdded (ValueTree&, ValueTree&) override { updateNumMessages(); } void valueTreeChildRemoved (ValueTree&, ValueTree&, int) override { updateNumMessages(); } diff --git a/extras/Projucer/Source/Project/UI/jucer_UserAvatarComponent.h b/extras/Projucer/Source/Project/UI/jucer_UserAvatarComponent.h index f48fac8d40..a51d8ec352 100644 --- a/extras/Projucer/Source/Project/UI/jucer_UserAvatarComponent.h +++ b/extras/Projucer/Source/Project/UI/jucer_UserAvatarComponent.h @@ -64,6 +64,11 @@ public: } void mouseUp (const MouseEvent&) override + { + triggerClick(); + } + + void triggerClick() { if (interactive) { @@ -76,6 +81,15 @@ public: bool isDisplaingGPLLogo() const noexcept { return isGPL; } + std::unique_ptr createAccessibilityHandler() override + { + return interactive ? std::make_unique (*this, + AccessibilityRole::button, + AccessibilityActions().addAction (AccessibilityActionType::press, + [this] { triggerClick(); })) + : nullptr; + } + private: //============================================================================== static Image createGPLAvatarImage() diff --git a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_MSVC.h b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_MSVC.h index fb44ee5a90..a6f3f7527b 100644 --- a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_MSVC.h +++ b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_MSVC.h @@ -845,6 +845,17 @@ public: { auto extraCompilerFlags = owner.compilerFlagSchemesMap[projectItem.getCompilerFlagSchemeString()].get().toString(); + if (shouldAddBigobjFlag (path)) + { + const String bigobjFlag ("/bigobj"); + + if (! extraCompilerFlags.contains (bigobjFlag)) + { + extraCompilerFlags << " " << bigobjFlag; + extraCompilerFlags.trim(); + } + } + if (extraCompilerFlags.isNotEmpty()) e->createNewChildElement ("AdditionalOptions")->addTextElement (extraCompilerFlags + " %(AdditionalOptions)"); @@ -1729,6 +1740,11 @@ protected: return path.getFileNameWithoutExtension().startsWithIgnoreCase ("include_juce_audio_plugin_client_RTAS_"); } + static bool shouldAddBigobjFlag (const build_tools::RelativePath& path) + { + return path.getFileNameWithoutExtension().equalsIgnoreCase ("include_juce_gui_basics"); + } + StringArray getModuleLibs() const { StringArray result; diff --git a/extras/Projucer/Source/Utility/UI/jucer_JucerTreeViewBase.cpp b/extras/Projucer/Source/Utility/UI/jucer_JucerTreeViewBase.cpp index 6ed687fb71..0189135617 100644 --- a/extras/Projucer/Source/Utility/UI/jucer_JucerTreeViewBase.cpp +++ b/extras/Projucer/Source/Utility/UI/jucer_JucerTreeViewBase.cpp @@ -119,9 +119,9 @@ void JucerTreeViewBase::paintContent (Graphics& g, Rectangle area) g.drawFittedText (getDisplayName(), area, Justification::centredLeft, 1, 1.0f); } -Component* JucerTreeViewBase::createItemComponent() +std::unique_ptr JucerTreeViewBase::createItemComponent() { - return new TreeItemComponent (*this); + return std::make_unique (*this); } //============================================================================== @@ -177,9 +177,9 @@ void JucerTreeViewBase::itemClicked (const MouseEvent& e) if (e.mods.isPopupMenu()) { if (getOwnerView()->getNumSelectedItems() > 1) - showMultiSelectionPopupMenu(); + showMultiSelectionPopupMenu (e.getMouseDownScreenPosition()); else - showPopupMenu(); + showPopupMenu (e.getMouseDownScreenPosition()); } else if (isSelected()) { @@ -187,29 +187,18 @@ void JucerTreeViewBase::itemClicked (const MouseEvent& e) } } -void JucerTreeViewBase::deleteItem() {} -void JucerTreeViewBase::deleteAllSelectedItems() {} -void JucerTreeViewBase::showDocument() {} -void JucerTreeViewBase::showPopupMenu() {} -void JucerTreeViewBase::showAddMenu() {} -void JucerTreeViewBase::showMultiSelectionPopupMenu() {} - static void treeViewMenuItemChosen (int resultCode, WeakReference item) { if (item != nullptr) item->handlePopupMenuResult (resultCode); } -void JucerTreeViewBase::launchPopupMenu (PopupMenu& m) +void JucerTreeViewBase::launchPopupMenu (PopupMenu& m, Point p) { - m.showMenuAsync (PopupMenu::Options(), + m.showMenuAsync (PopupMenu::Options().withTargetScreenArea ({ p.x, p.y, 1, 1 }), ModalCallbackFunction::create (treeViewMenuItemChosen, WeakReference (this))); } -void JucerTreeViewBase::handlePopupMenuResult (int) -{ -} - ProjectContentComponent* JucerTreeViewBase::getProjectContentComponent() const { for (Component* c = getOwnerView(); c != nullptr; c = c->getParentComponent()) diff --git a/extras/Projucer/Source/Utility/UI/jucer_JucerTreeViewBase.h b/extras/Projucer/Source/Utility/UI/jucer_JucerTreeViewBase.h index d560db2d8c..e7d79c0328 100644 --- a/extras/Projucer/Source/Utility/UI/jucer_JucerTreeViewBase.h +++ b/extras/Projucer/Source/Utility/UI/jucer_JucerTreeViewBase.h @@ -44,8 +44,9 @@ public: void itemClicked (const MouseEvent& e) override; void itemSelectionChanged (bool isNowSelected) override; void itemDoubleClicked (const MouseEvent&) override; - Component* createItemComponent() override; - String getTooltip() override { return {}; } + std::unique_ptr createItemComponent() override; + String getTooltip() override { return {}; } + String getAccessibilityName() override { return getDisplayName(); } void cancelDelayedSelectionTimer(); @@ -67,17 +68,18 @@ public: virtual File getDraggableFile() const { return {}; } void refreshSubItems(); - virtual void deleteItem(); - virtual void deleteAllSelectedItems(); - virtual void showDocument(); - virtual void showMultiSelectionPopupMenu(); - virtual void showRenameBox(); - - void launchPopupMenu (PopupMenu&); // runs asynchronously, and produces a callback to handlePopupMenuResult(). - virtual void showPopupMenu(); - virtual void showAddMenu(); - virtual void handlePopupMenuResult (int resultCode); - virtual void setSearchFilter (const String&) {} + void showRenameBox(); + + virtual void deleteItem() {} + virtual void deleteAllSelectedItems() {} + virtual void showDocument() {} + virtual void showMultiSelectionPopupMenu (Point) {} + virtual void showPopupMenu (Point) {} + virtual void showAddMenu (Point) {} + virtual void handlePopupMenuResult (int) {} + virtual void setSearchFilter (const String&) {} + + void launchPopupMenu (PopupMenu&, Point); // runs asynchronously, and produces a callback to handlePopupMenuResult(). //============================================================================== // To handle situations where an item gets deleted before openness is @@ -187,7 +189,7 @@ public: tree.clearSelectedItems(); if (e.mods.isRightButtonDown()) - rootItem->showPopupMenu(); + rootItem->showPopupMenu (e.getMouseDownScreenPosition()); } } @@ -205,6 +207,7 @@ class TreeItemComponent : public Component public: TreeItemComponent (JucerTreeViewBase& i) : item (&i) { + setAccessible (false); setInterceptsMouseClicks (false, true); item->textX = iconWidth; }