From 84d438aebc79ca0b6243015638c041f170315694 Mon Sep 17 00:00:00 2001 From: jules Date: Fri, 18 Nov 2011 13:50:19 +0000 Subject: [PATCH] Revamped the introjucer's settings page, making it easier to navigate than the old tabbed layout. Also, tweaked Viewport to be more resilient to changes in its content's size. --- extras/Introjucer/Builds/Linux/Makefile | 4 +- .../jucer_AudioPluginFilterTemplate.cpp | 2 +- .../jucer_AudioPluginFilterTemplate.h | 2 +- .../jucer_MainConsoleAppTemplate.cpp | 2 +- .../BinaryData/jucer_WindowTemplate.cpp | 2 +- .../Source/BinaryData/jucer_WindowTemplate.h | 2 +- .../Project Saving/jucer_ProjectSaver.h | 14 - .../jucer_ProjectInformationComponent.cpp | 1221 ++++++++++------- .../jucer_ProjectInformationComponent.h | 28 +- .../geometry/juce_RectangleList.cpp | 54 +- .../juce_gui_basics/layout/juce_Viewport.cpp | 62 +- .../positioning/juce_RelativeRectangle.cpp | 2 +- .../opengl/juce_OpenGLGraphicsContext.cpp | 4 +- 13 files changed, 779 insertions(+), 620 deletions(-) diff --git a/extras/Introjucer/Builds/Linux/Makefile b/extras/Introjucer/Builds/Linux/Makefile index 4aa76799c4..ab958e7a34 100644 --- a/extras/Introjucer/Builds/Linux/Makefile +++ b/extras/Introjucer/Builds/Linux/Makefile @@ -20,7 +20,7 @@ ifeq ($(CONFIG),Debug) CPPFLAGS := $(DEPFLAGS) -D "LINUX=1" -D "DEBUG=1" -D "_DEBUG=1" -D "JUCER_LINUX_MAKE_7346DA2A=1" -I "/usr/include" -I "/usr/include/freetype2" -I "../../JuceLibraryCode" CFLAGS += $(CPPFLAGS) $(TARGET_ARCH) -g -ggdb -O0 CXXFLAGS += $(CFLAGS) - LDFLAGS += -L$(BINDIR) -L$(LIBDIR) -L"/usr/X11R6/lib/" -L"../../../../../juce/bin" -lfreetype -lpthread -lrt -lX11 -lGL -lGLU -lXinerama -lasound + LDFLAGS += -L$(BINDIR) -L$(LIBDIR) -L"/usr/X11R6/lib/" -L"../../../../../juce/bin" -lfreetype -lpthread -lrt -lX11 -lGL -lGLU -lXinerama -lasound -lXext LDDEPS := RESFLAGS := -D "LINUX=1" -D "DEBUG=1" -D "_DEBUG=1" -D "JUCER_LINUX_MAKE_7346DA2A=1" -I "/usr/include" -I "/usr/include/freetype2" -I "../../JuceLibraryCode" TARGET := Introjucer @@ -35,7 +35,7 @@ ifeq ($(CONFIG),Release) CPPFLAGS := $(DEPFLAGS) -D "LINUX=1" -D "NDEBUG=1" -D "JUCER_LINUX_MAKE_7346DA2A=1" -I "/usr/include" -I "/usr/include/freetype2" -I "../../JuceLibraryCode" CFLAGS += $(CPPFLAGS) $(TARGET_ARCH) -O3 CXXFLAGS += $(CFLAGS) - LDFLAGS += -L$(BINDIR) -L$(LIBDIR) -L"/usr/X11R6/lib/" -L"../../../../../juce/bin" -lfreetype -lpthread -lrt -lX11 -lGL -lGLU -lXinerama -lasound + LDFLAGS += -L$(BINDIR) -L$(LIBDIR) -L"/usr/X11R6/lib/" -L"../../../../../juce/bin" -lfreetype -lpthread -lrt -lX11 -lGL -lGLU -lXinerama -lasound -lXext LDDEPS := RESFLAGS := -D "LINUX=1" -D "NDEBUG=1" -D "JUCER_LINUX_MAKE_7346DA2A=1" -I "/usr/include" -I "/usr/include/freetype2" -I "../../JuceLibraryCode" TARGET := Introjucer diff --git a/extras/Introjucer/Source/BinaryData/jucer_AudioPluginFilterTemplate.cpp b/extras/Introjucer/Source/BinaryData/jucer_AudioPluginFilterTemplate.cpp index 56ab9425bf..e826aef0a8 100644 --- a/extras/Introjucer/Source/BinaryData/jucer_AudioPluginFilterTemplate.cpp +++ b/extras/Introjucer/Source/BinaryData/jucer_AudioPluginFilterTemplate.cpp @@ -1,7 +1,7 @@ /* ============================================================================== - This file was auto-generated by the Jucer! + This file was auto-generated! It contains the basic startup code for a Juce application. diff --git a/extras/Introjucer/Source/BinaryData/jucer_AudioPluginFilterTemplate.h b/extras/Introjucer/Source/BinaryData/jucer_AudioPluginFilterTemplate.h index 11c1f69621..fd976734d5 100644 --- a/extras/Introjucer/Source/BinaryData/jucer_AudioPluginFilterTemplate.h +++ b/extras/Introjucer/Source/BinaryData/jucer_AudioPluginFilterTemplate.h @@ -1,7 +1,7 @@ /* ============================================================================== - This file was auto-generated by the Jucer! + This file was auto-generated! It contains the basic startup code for a Juce application. diff --git a/extras/Introjucer/Source/BinaryData/jucer_MainConsoleAppTemplate.cpp b/extras/Introjucer/Source/BinaryData/jucer_MainConsoleAppTemplate.cpp index 2612f392c4..4fb8dde760 100644 --- a/extras/Introjucer/Source/BinaryData/jucer_MainConsoleAppTemplate.cpp +++ b/extras/Introjucer/Source/BinaryData/jucer_MainConsoleAppTemplate.cpp @@ -1,7 +1,7 @@ /* ============================================================================== - This file was auto-generated by the Jucer! + This file was auto-generated! It contains the basic startup code for a Juce application. diff --git a/extras/Introjucer/Source/BinaryData/jucer_WindowTemplate.cpp b/extras/Introjucer/Source/BinaryData/jucer_WindowTemplate.cpp index b6464917e0..dfd4b54427 100644 --- a/extras/Introjucer/Source/BinaryData/jucer_WindowTemplate.cpp +++ b/extras/Introjucer/Source/BinaryData/jucer_WindowTemplate.cpp @@ -1,7 +1,7 @@ /* ============================================================================== - This file was auto-generated by the Jucer! + This file was auto-generated! It contains the basic outline for a simple desktop window. diff --git a/extras/Introjucer/Source/BinaryData/jucer_WindowTemplate.h b/extras/Introjucer/Source/BinaryData/jucer_WindowTemplate.h index a4df1854a9..52832f0ba9 100644 --- a/extras/Introjucer/Source/BinaryData/jucer_WindowTemplate.h +++ b/extras/Introjucer/Source/BinaryData/jucer_WindowTemplate.h @@ -1,7 +1,7 @@ /* ============================================================================== - This file was auto-generated by the Jucer! + This file was auto-generated! It contains the basic outline for a simple desktop window. diff --git a/extras/Introjucer/Source/Project Saving/jucer_ProjectSaver.h b/extras/Introjucer/Source/Project Saving/jucer_ProjectSaver.h index b5d5ed1c7a..125a1ef719 100644 --- a/extras/Introjucer/Source/Project Saving/jucer_ProjectSaver.h +++ b/extras/Introjucer/Source/Project Saving/jucer_ProjectSaver.h @@ -213,20 +213,6 @@ private: if (xml != nullptr) { - #if JUCE_DEBUG - { - MemoryOutputStream mo; - project.getProjectRoot().writeToStream (mo); - - MemoryInputStream mi (mo.getData(), mo.getDataSize(), false); - ValueTree v = ValueTree::readFromStream (mi); - ScopedPointer xml2 (v.createXml()); - - // This bit just tests that ValueTree save/load works reliably.. Let me know if this asserts for you! - jassert (xml->isEquivalentTo (xml2, true)); - } - #endif - MemoryOutputStream mo; xml->writeToStream (mo, String::empty); replaceFileIfDifferent (projectFile, mo); diff --git a/extras/Introjucer/Source/Project/jucer_ProjectInformationComponent.cpp b/extras/Introjucer/Source/Project/jucer_ProjectInformationComponent.cpp index 447d5bfe33..84e6ad2e4e 100644 --- a/extras/Introjucer/Source/Project/jucer_ProjectInformationComponent.cpp +++ b/extras/Introjucer/Source/Project/jucer_ProjectInformationComponent.cpp @@ -1,17 +1,17 @@ /* ============================================================================== - This is an automatically generated file created by the Jucer! + This is an automatically generated file! Be careful when adding custom code to these files, as only the code within the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded and re-saved. - Created for JUCE version: JUCE v1.53.8 + Created for JUCE version: JUCE v2.0.9 ------------------------------------------------------------------------------ - JUCE and the Jucer are copyright 2004-10 by Raw Material Software ltd. + JUCE is copyright 2004-11 by Raw Material Software ltd. ============================================================================== */ @@ -27,355 +27,16 @@ //[MiscUserDefs] You can add your own user definitions and misc code here... -//============================================================================== -class PanelBase : public PropertyPanelWithTooltips -{ -public: - PanelBase (Project& project_) : project (project_) {} - - virtual void rebuildProperties (Array & props) = 0; - - void visibilityChanged() - { - if (isVisible()) - refreshAll(); - } - - void refreshAll() - { - getPanel().clear(); - Array props; - rebuildProperties (props); - getPanel().addProperties (props); - } - -protected: - Project& project; -}; //============================================================================== -class ProjectTab : public PanelBase -{ -public: - ProjectTab (Project& project_) : PanelBase (project_) {} - - void rebuildProperties (Array & props) - { - project.createPropertyEditors (props); - } -}; - -//============================================================================== -class ConfigTab : public PanelBase -{ -public: - ConfigTab (Project& project_, int configIndex_) - : PanelBase (project_), configIndex (configIndex_) - { - } - - void rebuildProperties (Array & props) - { - project.getConfiguration (configIndex).createPropertyEditors (props); - } - -private: - int configIndex; -}; - -//============================================================================== -class ExportTab : public PanelBase -{ -public: - ExportTab (Project& project_, int exporterIndex_) - : PanelBase (project_), exporterIndex (exporterIndex_) - { - } - - void rebuildProperties (Array & props) - { - ScopedPointer exp (project.createExporter (exporterIndex)); - - if (exp != nullptr) - exp->createPropertyEditors (props); - - for (int i = props.size(); --i >= 0;) - props.getUnchecked(i)->setPreferredHeight (22); - } - -private: - int exporterIndex; -}; - -//============================================================================== -class ModuleSettingsPanel : public PanelBase -{ -public: - ModuleSettingsPanel (Project& project_, ModuleList& moduleList_, const String& moduleID_) - : PanelBase (project_), moduleList (moduleList_), moduleID (moduleID_) - { - setBounds ("parent.width / 2 + 1, 31, parent.width - 3, parent.height - 3"); - } - - void rebuildProperties (Array & props) - { - ScopedPointer module (moduleList.loadModule (moduleID)); - - if (module != nullptr) - { - props.add (new ModuleInfoComponent (project, moduleList, moduleID)); - - if (project.isModuleEnabled (moduleID)) - { - const ModuleList::Module* m = moduleList.findModuleInfo (moduleID); - if (m != nullptr && moduleList.getExtraDependenciesNeeded (project, *m).size() > 0) - props.add (new MissingDependenciesComponent (project, moduleList, moduleID)); - } - - props.add (new BooleanPropertyComponent (project.shouldShowAllModuleFilesInProject (moduleID), - "Add source to project", "Make module files browsable in projects")); - props.getLast()->setTooltip ("If this is enabled, then the entire source tree from this module will be shown inside your project, " - "making it easy to browse/edit the module's classes. If disabled, then only the minimum number of files " - "required to compile it will appear inside your project."); - - props.add (new BooleanPropertyComponent (project.shouldCopyModuleFilesLocally (moduleID), - "Create local copy", "Copy the module into the project folder")); - props.getLast()->setTooltip ("If this is enabled, then a local copy of the entire module will be made inside your project (in the auto-generated JuceLibraryFiles folder), " - "so that your project will be self-contained, and won't need to contain any references to files in other folders. " - "This also means that you can check the module into your source-control system to make sure it is always in sync with your own code."); - - StringArray possibleValues; - possibleValues.add ("(Use Default)"); - possibleValues.add ("Enabled"); - possibleValues.add ("Disabled"); - - Array mappings; - mappings.add (Project::configFlagDefault); - mappings.add (Project::configFlagEnabled); - mappings.add (Project::configFlagDisabled); - - OwnedArray flags; - module->getConfigFlags (project, flags); - - for (int i = 0; i < flags.size(); ++i) - { - ChoicePropertyComponent* c = new ChoicePropertyComponent (flags[i]->value, flags[i]->symbol, possibleValues, mappings); - c->setTooltip (flags[i]->description); - c->setPreferredHeight (22); - props.add (c); - } - } - - setEnabled (project.isModuleEnabled (moduleID)); - } - -private: - ModuleList& moduleList; - String moduleID; - - //============================================================================== - class ModuleInfoComponent : public PropertyComponent - { - public: - ModuleInfoComponent (Project& project_, ModuleList& moduleList_, const String& moduleID_) - : PropertyComponent ("Module", 100), - project (project_), moduleList (moduleList_), moduleID (moduleID_) - { - } - - void refresh() {} - - void paint (Graphics& g) - { - g.setColour (Colours::white.withAlpha (0.4f)); - g.fillRect (0, 0, getWidth(), getHeight() - 1); - - const ModuleList::Module* module = moduleList.findModuleInfo (moduleID); - - if (module != nullptr) - { - String text; - text << module->name << newLine << "Version: " << module->version << newLine << newLine - << module->description; - - GlyphArrangement ga; - ga.addJustifiedText (Font (13.0f), text, 4.0f, 16.0f, getWidth() - 8.0f, Justification::topLeft); - g.setColour (Colours::black); - ga.draw (g); - } - } - - private: - Project& project; - ModuleList& moduleList; - String moduleID; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ModuleInfoComponent); - }; - - //============================================================================== - class MissingDependenciesComponent : public PropertyComponent, - public ButtonListener - { - public: - MissingDependenciesComponent (Project& project_, ModuleList& moduleList_, const String& moduleID_) - : PropertyComponent ("Dependencies", 100), - project (project_), moduleList (moduleList_), moduleID (moduleID_), - fixButton ("Enable Required Modules") - { - const ModuleList::Module* module = moduleList.findModuleInfo (moduleID); - - if (module != nullptr) - missingDependencies = moduleList.getExtraDependenciesNeeded (project, *module); - - addAndMakeVisible (&fixButton); - fixButton.setColour (TextButton::buttonColourId, Colours::red); - fixButton.setColour (TextButton::textColourOffId, Colours::white); - fixButton.setBounds ("right - 160, parent.height - 26, parent.width - 8, top + 22"); - fixButton.addListener (this); - } - - void refresh() {} - - void paint (Graphics& g) - { - g.setColour (Colours::white.withAlpha (0.4f)); - g.fillRect (0, 0, getWidth(), getHeight() - 1); - - String text ("This module requires the following dependencies:\n"); - text << missingDependencies.joinIntoString (", "); - - GlyphArrangement ga; - ga.addJustifiedText (Font (13.0f), text, 4.0f, 16.0f, getWidth() - 8.0f, Justification::topLeft); - g.setColour (Colours::red); - ga.draw (g); - } - - void buttonClicked (Button*); - - private: - Project& project; - ModuleList& moduleList; - String moduleID; - StringArray missingDependencies; - TextButton fixButton; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MissingDependenciesComponent); - }; -}; - -//============================================================================== -class ModuleSelectionListBox : public ListBox, - public ListBoxModel -{ -public: - ModuleSelectionListBox (ModuleList& list_) - : list (list_), handler (nullptr) - { - setColour (ListBox::backgroundColourId, Colours::white.withAlpha (0.4f)); - } - - void refresh() - { - updateContent(); - repaint(); - } - - int getNumRows() - { - return list.modules.size(); - } - - void paintListBoxItem (int rowNumber, Graphics& g, int width, int height, bool rowIsSelected) - { - if (rowIsSelected) - g.fillAll (findColour (TextEditor::highlightColourId)); - - const ModuleList::Module* const m = list.modules [rowNumber]; - - if (m != nullptr) - { - const float tickSize = height * 0.7f; - - getLookAndFeel().drawTickBox (g, *this, (height - tickSize) / 2, (height - tickSize) / 2, tickSize, tickSize, - handler->isEnabled (m), true, false, false); - - if (handler->isEnabled (m) && handler->areDependenciesMissing (m)) - g.setColour (Colours::red); - else - g.setColour (Colours::black); - - g.setFont (height * 0.7f, Font::bold); - g.drawFittedText (m->uid, height, 0, 200, height, Justification::centredLeft, 1); - - g.setFont (height * 0.55f, Font::italic); - g.drawText (m->name, height + 200, 0, width - height - 200, height, Justification::centredLeft, true); - } - } - - void listBoxItemClicked (int row, const MouseEvent& e) - { - if (e.x < getRowHeight()) - flipRow (row); - } - - void listBoxItemDoubleClicked (int row, const MouseEvent& e) - { - flipRow (row); - } - - void returnKeyPressed (int row) - { - flipRow (row); - } - - void selectedRowsChanged (int lastRowSelected) - { - handler->selectionChanged (list.modules [lastRowSelected]); - } - - void flipRow (int row) - { - const ModuleList::Module* const m = list.modules [row]; - - if (m != nullptr) - handler->setEnabled (m, ! handler->isEnabled (m)); - } - - //============================================================================== - class Handler - { - public: - Handler() {} - virtual ~Handler() {}; - - virtual bool isEnabled (const ModuleList::Module* m) const = 0; - virtual void setEnabled (const ModuleList::Module* m, bool enable) = 0; - virtual bool areDependenciesMissing (const ModuleList::Module* m) = 0; - virtual void selectionChanged (const ModuleList::Module* selectedModule) = 0; - }; - - void setHandler (Handler* h) - { - handler = h; - setModel (this); - } - -private: - ModuleList& list; - Handler* handler; -}; - - -//============================================================================== -class ModulesPanel : public Component, - public ModuleSelectionListBox::Handler, +class ModulesPanel : public PropertyComponent, public FilenameComponentListener, public ButtonListener { public: ModulesPanel (Project& project_) - : project (project_), + : PropertyComponent ("Modules", 500), + project (project_), modulesLocation ("modules", ModuleList::getLocalModulesFolder (&project), true, true, false, "*", String::empty, "Select a folder containing your JUCE modules..."), @@ -395,7 +56,7 @@ public: updateModulesButton.setBounds ("parent.width - 175, 3, parent.width - 4, 28"); updateModulesButton.addListener (this); - moduleListBox.setHandler (this); + moduleListBox.setOwner (this); addAndMakeVisible (&moduleListBox); moduleListBox.setBounds ("4, 31, parent.width / 2 - 4, parent.height - 3"); } @@ -451,6 +112,275 @@ public: settings->refreshAll(); } + void paint (Graphics& g) // (overridden to avoid drawing the name) + { + getLookAndFeel().drawPropertyComponentBackground (g, getWidth(), getHeight(), *this); + } + + //============================================================================== + class ModuleSelectionListBox : public ListBox, + public ListBoxModel + { + public: + ModuleSelectionListBox (ModuleList& list_) + : list (list_), owner (nullptr) + { + setColour (ListBox::backgroundColourId, Colours::white.withAlpha (0.4f)); + setTooltip ("Use this list to select which modules should be included in your app.\n" + "Any modules which have missing dependencies will be shown in red."); + } + + void setOwner (ModulesPanel* owner_) + { + owner = owner_; + setModel (this); + } + + void refresh() + { + updateContent(); + repaint(); + } + + int getNumRows() + { + return list.modules.size(); + } + + void paintListBoxItem (int rowNumber, Graphics& g, int width, int height, bool rowIsSelected) + { + if (rowIsSelected) + g.fillAll (findColour (TextEditor::highlightColourId)); + + const ModuleList::Module* const m = list.modules [rowNumber]; + + if (m != nullptr) + { + const float tickSize = height * 0.7f; + + getLookAndFeel().drawTickBox (g, *this, (height - tickSize) / 2, (height - tickSize) / 2, tickSize, tickSize, + owner->isEnabled (m), true, false, false); + + if (owner->isEnabled (m) && owner->areDependenciesMissing (m)) + g.setColour (Colours::red); + else + g.setColour (Colours::black); + + g.setFont (height * 0.7f, Font::bold); + g.drawFittedText (m->uid, height, 0, 200, height, Justification::centredLeft, 1); + + g.setFont (height * 0.55f, Font::italic); + g.drawText (m->name, height + 200, 0, width - height - 200, height, Justification::centredLeft, true); + } + } + + void listBoxItemClicked (int row, const MouseEvent& e) + { + if (e.x < getRowHeight()) + flipRow (row); + } + + void listBoxItemDoubleClicked (int row, const MouseEvent& e) + { + flipRow (row); + } + + void returnKeyPressed (int row) + { + flipRow (row); + } + + void selectedRowsChanged (int lastRowSelected) + { + owner->selectionChanged (list.modules [lastRowSelected]); + } + + void flipRow (int row) + { + const ModuleList::Module* const m = list.modules [row]; + + if (m != nullptr) + owner->setEnabled (m, ! owner->isEnabled (m)); + } + + private: + ModuleList& list; + ModulesPanel* owner; + }; + + //============================================================================== + class ModuleSettingsPanel : public PropertyPanel + { + public: + ModuleSettingsPanel (Project& project_, ModuleList& moduleList_, const String& moduleID_) + : project (project_), moduleList (moduleList_), moduleID (moduleID_) + { + setBounds ("parent.width / 2 + 1, 31, parent.width - 3, parent.height - 3"); + refreshAll(); + } + + void refreshAll() + { + setEnabled (project.isModuleEnabled (moduleID)); + + clear(); + Array props; + + ScopedPointer module (moduleList.loadModule (moduleID)); + + if (module != nullptr) + { + props.add (new ModuleInfoComponent (project, moduleList, moduleID)); + + if (project.isModuleEnabled (moduleID)) + { + const ModuleList::Module* m = moduleList.findModuleInfo (moduleID); + if (m != nullptr && moduleList.getExtraDependenciesNeeded (project, *m).size() > 0) + props.add (new MissingDependenciesComponent (project, moduleList, moduleID)); + } + + props.add (new BooleanPropertyComponent (project.shouldShowAllModuleFilesInProject (moduleID), + "Add source to project", "Make module files browsable in projects")); + props.getLast()->setTooltip ("If this is enabled, then the entire source tree from this module will be shown inside your project, " + "making it easy to browse/edit the module's classes. If disabled, then only the minimum number of files " + "required to compile it will appear inside your project."); + + props.add (new BooleanPropertyComponent (project.shouldCopyModuleFilesLocally (moduleID), + "Create local copy", "Copy the module into the project folder")); + props.getLast()->setTooltip ("If this is enabled, then a local copy of the entire module will be made inside your project (in the auto-generated JuceLibraryFiles folder), " + "so that your project will be self-contained, and won't need to contain any references to files in other folders. " + "This also means that you can check the module into your source-control system to make sure it is always in sync with your own code."); + + StringArray possibleValues; + possibleValues.add ("(Use Default)"); + possibleValues.add ("Enabled"); + possibleValues.add ("Disabled"); + + Array mappings; + mappings.add (Project::configFlagDefault); + mappings.add (Project::configFlagEnabled); + mappings.add (Project::configFlagDisabled); + + OwnedArray flags; + module->getConfigFlags (project, flags); + + for (int i = 0; i < flags.size(); ++i) + { + ChoicePropertyComponent* c = new ChoicePropertyComponent (flags[i]->value, flags[i]->symbol, possibleValues, mappings); + c->setTooltip (flags[i]->description); + c->setPreferredHeight (22); + props.add (c); + } + } + + addProperties (props); + } + + private: + Project& project; + ModuleList& moduleList; + String moduleID; + + //============================================================================== + class ModuleInfoComponent : public PropertyComponent + { + public: + ModuleInfoComponent (Project& project_, ModuleList& moduleList_, const String& moduleID_) + : PropertyComponent ("Module", 100), project (project_), moduleList (moduleList_), moduleID (moduleID_) + { + } + + void refresh() {} + + void paint (Graphics& g) + { + g.setColour (Colours::white.withAlpha (0.4f)); + g.fillRect (0, 0, getWidth(), getHeight() - 1); + + const ModuleList::Module* module = moduleList.findModuleInfo (moduleID); + + if (module != nullptr) + { + String text; + text << module->name << newLine << "Version: " << module->version << newLine << newLine + << module->description; + + GlyphArrangement ga; + ga.addJustifiedText (Font (13.0f), text, 4.0f, 16.0f, getWidth() - 8.0f, Justification::topLeft); + g.setColour (Colours::black); + ga.draw (g); + } + } + + private: + Project& project; + ModuleList& moduleList; + String moduleID; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ModuleInfoComponent); + }; + + //============================================================================== + class MissingDependenciesComponent : public PropertyComponent, + public ButtonListener + { + public: + MissingDependenciesComponent (Project& project_, ModuleList& moduleList_, const String& moduleID_) + : PropertyComponent ("Dependencies", 100), + project (project_), moduleList (moduleList_), moduleID (moduleID_), + fixButton ("Enable Required Modules") + { + const ModuleList::Module* module = moduleList.findModuleInfo (moduleID); + + if (module != nullptr) + missingDependencies = moduleList.getExtraDependenciesNeeded (project, *module); + + addAndMakeVisible (&fixButton); + fixButton.setColour (TextButton::buttonColourId, Colours::red); + fixButton.setColour (TextButton::textColourOffId, Colours::white); + fixButton.setBounds ("right - 160, parent.height - 26, parent.width - 8, top + 22"); + fixButton.addListener (this); + } + + void refresh() {} + + void paint (Graphics& g) + { + g.setColour (Colours::white.withAlpha (0.4f)); + g.fillRect (0, 0, getWidth(), getHeight() - 1); + + String text ("This module requires the following dependencies:\n"); + text << missingDependencies.joinIntoString (", "); + + GlyphArrangement ga; + ga.addJustifiedText (Font (13.0f), text, 4.0f, 16.0f, getWidth() - 8.0f, Justification::topLeft); + g.setColour (Colours::red); + ga.draw (g); + } + + void buttonClicked (Button*) + { + bool isModuleCopiedLocally = project.shouldCopyModuleFilesLocally (moduleID).getValue(); + + for (int i = missingDependencies.size(); --i >= 0;) + project.addModule (missingDependencies[i], isModuleCopiedLocally); + + ModulesPanel* mp = findParentComponentOfClass ((ModulesPanel*) nullptr); + if (mp != nullptr) + mp->refresh(); + } + + private: + Project& project; + ModuleList& moduleList; + String moduleID; + StringArray missingDependencies; + TextButton fixButton; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MissingDependenciesComponent); + }; + }; + private: Project& project; ModuleList moduleList; @@ -461,46 +391,433 @@ private: ScopedPointer settings; }; -void ModuleSettingsPanel::MissingDependenciesComponent::buttonClicked (Button*) + +//============================================================================== +class ProjectSettingsComponent : public Component { - bool isModuleCopiedLocally = project.shouldCopyModuleFilesLocally (moduleID).getValue(); +public: + ProjectSettingsComponent (Project& project_) + : project (project_), + configs ("Configurations", "Add a New Configuration", false), + exporters ("Export Targets", "Add a New Exporter...", true) + { + addAndMakeVisible (&mainProjectInfoPanel); + addAndMakeVisible (&modulesPanelGroup); + addAndMakeVisible (&configs); + addAndMakeVisible (&exporters); - for (int i = missingDependencies.size(); --i >= 0;) - project.addModule (missingDependencies[i], isModuleCopiedLocally); + Array props; + props.add (new ModulesPanel (project)); + modulesPanelGroup.setProperties (props); + modulesPanelGroup.setName ("Modules"); - ModulesPanel* mp = findParentComponentOfClass ((ModulesPanel*) 0); - if (mp != nullptr) - mp->refresh(); -} + createItems(); + } + + void updateSize (int width) + { + width = jmax (550, width); + + int y = 0; + y += mainProjectInfoPanel.updateSize (y, width); + y += modulesPanelGroup.updateSize (y, width); + y += configs.updateSize (y, width); + y += exporters.updateSize (y, width); + + setSize (width, y); + } + + void parentSizeChanged() + { + updateSize (getParentWidth()); + } + + void visibilityChanged() + { + if (isVisible()) + refreshAll(); + } + + void refreshAll() + { + { + Array props; + project.createPropertyEditors (props); + mainProjectInfoPanel.setProperties (props); + mainProjectInfoPanel.setName ("Project Settings"); + } + + int i; + for (i = configs.groups.size(); --i >= 0;) + { + PropertyGroup& pp = *configs.groups.getUnchecked(i); + + Array props; + project.getConfiguration (i).createPropertyEditors (props); + pp.setProperties (props); + } + + for (i = exporters.groups.size(); --i >= 0;) + { + PropertyGroup& pp = *exporters.groups.getUnchecked(i); + Array props; + ScopedPointer exp (project.createExporter (i)); + + jassert (exp != nullptr); + if (exp != nullptr) + { + exp->createPropertyEditors (props); + + for (int j = props.size(); --j >= 0;) + props.getUnchecked(j)->setPreferredHeight (22); + + pp.setProperties (props); + } + } + + refreshSectionNames(); + + updateSize (getWidth()); + } + + void refreshSectionNames() + { + int i; + for (i = configs.groups.size(); --i >= 0;) + { + PropertyGroup& pp = *configs.groups.getUnchecked(i); + pp.setName (project.getConfiguration (i).getName().toString().quoted()); + pp.repaint(); + } + + for (i = exporters.groups.size(); --i >= 0;) + { + PropertyGroup& pp = *exporters.groups.getUnchecked(i); + ScopedPointer exp (project.createExporter (i)); + + jassert (exp != nullptr); + if (exp != nullptr) + pp.setName (exp->getName()); + + pp.repaint(); + } + } + + void createItems() + { + configs.clear(); + exporters.clear(); + + int i; + for (i = 0; i < project.getNumConfigurations(); ++i) + { + PropertyGroup* p = configs.createGroup(); + + if (project.getNumConfigurations() > 1) + p->addDeleteButton ("config " + String (i), "Deletes this configuration."); + } + + for (i = 0; i < project.getNumExporters(); ++i) + { + PropertyGroup* p = exporters.createGroup(); + p->addDeleteButton ("exporter " + String (i), "Deletes this export target."); + } + + lastProjectType = project.getProjectTypeValue().getValue(); + refreshAll(); + } + + void update() + { + if (configs.groups.size() != project.getNumConfigurations() + || exporters.groups.size() != project.getNumExporters() + || lastProjectType != project.getProjectTypeValue().getValue()) + { + createItems(); + } + + refreshSectionNames(); + } + + void deleteButtonClicked (const String& name) + { + if (name.startsWith ("config")) + project.deleteConfiguration (name.getTrailingIntValue()); + else + project.deleteExporter (name.getTrailingIntValue()); + } + + void createNewExporter (TextButton& button) + { + StringArray exporters (ProjectExporter::getExporterNames()); + PopupMenu menu; + + for (int i = 0; i < exporters.size(); ++i) + menu.addItem (i + 1, "Create a new " + exporters[i] + " target"); + + const int r = menu.showAt (&button); + + if (r > 0) + project.addNewExporter (exporters [r - 1]); + } + + void createNewConfig() + { + project.addNewConfiguration (nullptr); + } + + void newItemButtonClicked (TextButton& button) + { + if (button.getName().containsIgnoreCase ("export")) + createNewExporter (button); + else + createNewConfig(); + } + +private: + //============================================================================== + class PropertyGroup : public Component, + public ButtonListener + { + public: + PropertyGroup() + : deleteButton ("Delete"), preferredHeight (0) + { + deleteButton.addListener (this); + } + + void addDeleteButton (const String& name, const String& tooltip) + { + addAndMakeVisible (&deleteButton); + deleteButton.setBounds ("right - 55, 11, parent.width - 10, 26"); + deleteButton.setColour (TextButton::buttonColourId, Colour (0xa0fcbdbd)); + deleteButton.setColour (TextButton::textColourOffId, Colours::darkred); + deleteButton.setConnectedEdges (Button::ConnectedOnLeft | Button::ConnectedOnRight); + deleteButton.setName (name); + deleteButton.setTooltip (tooltip); + } + + void setProperties (const Array& newProps) + { + properties.clear(); + properties.addArray (newProps); + + preferredHeight = 32; + for (int i = properties.size(); --i >= 0;) + { + addAndMakeVisible (properties.getUnchecked(i)); + preferredHeight += properties.getUnchecked(i)->getPreferredHeight(); + } + } + + int getPreferredHeight() const + { + return preferredHeight; + } + + int updateSize (int y, int width) + { + setBounds (0, y, width, preferredHeight); + + y = 30; + for (int i = 0; i < properties.size(); ++i) + { + PropertyComponent* pp = properties.getUnchecked(i); + pp->setBounds (10, y, width - 20, pp->getPreferredHeight()); + y += pp->getHeight(); + } + + return preferredHeight; + } + + void paint (Graphics& g) + { + g.setFont (14.0f, Font::bold); + g.setColour (Colours::black); + g.drawFittedText (getName(), 12, 0, getWidth() - 16, 28, Justification::bottomLeft, 1); + } + + void buttonClicked (Button*) + { + ProjectSettingsComponent* psc = findParentComponentOfClass ((ProjectSettingsComponent*) nullptr); + if (psc != nullptr) + psc->deleteButtonClicked (deleteButton.getName()); + } + + private: + OwnedArray properties; + TextButton deleteButton; + int preferredHeight; + }; + + //============================================================================== + class PropertyGroupList : public Component, + public ButtonListener + { + public: + PropertyGroupList (const String& title, const String& newButtonText, bool triggerOnMouseDown) + : Component (title), createNewButton (newButtonText) + { + addAndMakeVisible (&createNewButton); + createNewButton.setColour (TextButton::buttonColourId, Colours::lightgreen.withAlpha (0.5f)); + createNewButton.setBounds ("right - 140, 30, parent.width - 10, top + 20"); + createNewButton.setConnectedEdges (Button::ConnectedOnLeft | Button::ConnectedOnRight); + createNewButton.addListener (this); + createNewButton.setTriggeredOnMouseDown (triggerOnMouseDown); + } + + int updateSize (int ourY, int width) + { + int y = 55; + + for (int i = 0; i < groups.size(); ++i) + y += groups.getUnchecked(i)->updateSize (y, width); + + y = jmax (y, 100); + setBounds (0, ourY, width, y); + return y; + } + + void paint (Graphics& g) + { + g.setFont (17.0f, Font::bold); + g.setColour (Colours::black); + g.drawFittedText (getName(), 0, 30, getWidth(), 20, Justification::centred, 1); + } + + void clear() + { + groups.clear(); + } + + PropertyGroup* createGroup() + { + PropertyGroup* p = new PropertyGroup(); + groups.add (p); + addAndMakeVisible (p); + return p; + } + + void buttonClicked (Button*) + { + ProjectSettingsComponent* psc = findParentComponentOfClass ((ProjectSettingsComponent*) nullptr); + if (psc != nullptr) + psc->newItemButtonClicked (createNewButton); + } + + OwnedArray groups; + TextButton createNewButton; + }; + + Project& project; + var lastProjectType; + PropertyGroup mainProjectInfoPanel, modulesPanelGroup; + PropertyGroupList configs, exporters; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ProjectSettingsComponent); +}; + +//============================================================================== +class ProjectInformationComponent::RolloverHelpComp : public Component, + private Timer +{ +public: + RolloverHelpComp() + : lastComp (nullptr) + { + startTimer (150); + } + + void paint (Graphics& g) + { + g.setColour (Colour::greyLevel (0.15f)); + g.setFont (13.0f); + + TextLayout tl; + tl.appendText (lastTip, Font (14.0f)); + tl.layout (getWidth() - 10, Justification::left, true); // try to make it look nice + if (tl.getNumLines() > 3) + tl.layout (getWidth() - 10, Justification::left, false); // too big, so just squash it in.. + + tl.drawWithin (g, 0, 0, getWidth(), getHeight(), Justification::centred); + } + + void timerCallback() + { + Component* newComp = Desktop::getInstance().getMainMouseSource().getComponentUnderMouse(); + + if (newComp != nullptr + && (newComp->getTopLevelComponent() != getTopLevelComponent() + || newComp->isCurrentlyBlockedByAnotherModalComponent())) + newComp = nullptr; + + if (newComp != lastComp) + { + lastComp = newComp; + + String newTip (findTip (newComp)); + + if (newTip != lastTip) + { + lastTip = newTip; + repaint(); + } + } + } + +private: + static String findTip (Component* c) + { + while (c != nullptr) + { + TooltipClient* const tc = dynamic_cast (c); + if (tc != nullptr) + { + const String tip (tc->getTooltip()); + + if (tip.isNotEmpty()) + return tip; + } + + c = c->getParentComponent(); + } + + return String::empty; + } + + TextLayout layout; + Component* lastComp; + String lastTip; +}; //[/MiscUserDefs] //============================================================================== ProjectInformationComponent::ProjectInformationComponent (Project& project_) - : project (project_), - configTabBox (TabbedButtonBar::TabsAtTop) + : project (project_) { - addAndMakeVisible (&configTabBox); - configTabBox.setBounds ("8, 0, this.left + parent.width - 16, this.top + parent.height - 36"); - addAndMakeVisible (&editConfigsButton); - editConfigsButton.setBounds ("8, parent.height - 30, this.left + 192, this.top + 22"); - editConfigsButton.setButtonText ("Add/Remove Configurations..."); - editConfigsButton.addListener (this); + addAndMakeVisible (&viewport); + viewport.setComponentID ("ykdBpb"); + viewport.setBounds (RelativeRectangle ("8, 8, parent.width - 8, parent.height - 74")); + viewport.setScrollBarThickness (16); addAndMakeVisible (&openProjectButton); - openProjectButton.setBounds ("608, parent.height - 30, this.left + 208, this.top + 22"); + openProjectButton.setComponentID ("a550a652e2666ee7"); + openProjectButton.setBounds (RelativeRectangle ("8, parent.height - 34, left + 227, top + 24")); openProjectButton.setButtonText ("Open Project in "); openProjectButton.addListener (this); - addAndMakeVisible (&editExportersButton); - editExportersButton.setBounds ("208, parent.height - 30, this.left + 160, this.top + 22"); - editExportersButton.setButtonText ("Add/Remove Exporters..."); - editExportersButton.addListener (this); + openProjectButton.setColour (TextButton::buttonColourId, Colour (0xffddddff)); addAndMakeVisible (&saveAndOpenButton); - saveAndOpenButton.setBounds ("391, parent.height - 30, this.left + 208, this.top + 22"); + saveAndOpenButton.setComponentID ("dRGMyYx"); + saveAndOpenButton.setBounds (RelativeRectangle ("8, parent.height - 65, left + 227, top + 24")); saveAndOpenButton.setButtonText ("Save And Open in"); saveAndOpenButton.addListener (this); + saveAndOpenButton.setColour (TextButton::buttonColourId, Colour (0xffddddff)); + addAndMakeVisible (rollover = new RolloverHelpComp()); + rollover->setComponentID ("QqLJBF"); + rollover->setBounds (RelativeRectangle ("246, parent.height - 68, parent.width - 8, parent.height - 4")); //[UserPreSize] - rebuildConfigTabs(); + viewport.setViewedComponent (new ProjectSettingsComponent (project), true); #if JUCE_MAC || JUCE_WINDOWS openProjectButton.setCommandToTrigger (commandManager, CommandIDs::openInIDE, true); @@ -514,14 +831,10 @@ ProjectInformationComponent::ProjectInformationComponent (Project& project_) #endif //[/UserPreSize] - setSize (836, 427); + setSize (808, 638); + //[Constructor] You can add your own custom stuff here.. - configTabBox.setOutline (1); - configTabBox.setColour (TabbedComponent::outlineColourId, Colours::black.withAlpha (0.3f)); - - editConfigsButton.setTriggeredOnMouseDown (true); - project.addChangeListener (this); //[/Constructor] } @@ -532,6 +845,7 @@ ProjectInformationComponent::~ProjectInformationComponent() project.removeChangeListener (this); //[/Destructor_pre] + rollover = 0; //[Destructor]. You can add your own custom destruction code here.. @@ -555,23 +869,11 @@ void ProjectInformationComponent::buttonClicked (Button* buttonThatWasClicked) //[UserbuttonClicked_Pre] //[/UserbuttonClicked_Pre] - if (buttonThatWasClicked == &editConfigsButton) - { - //[UserButtonCode_b6625dfcdb1f4755] -- add your button handler code here.. - showConfigMenu(); - //[/UserButtonCode_b6625dfcdb1f4755] - } - else if (buttonThatWasClicked == &openProjectButton) + if (buttonThatWasClicked == &openProjectButton) { //[UserButtonCode_a550a652e2666ee7] -- add your button handler code here.. //[/UserButtonCode_a550a652e2666ee7] } - else if (buttonThatWasClicked == &editExportersButton) - { - //[UserButtonCode_c1f6e5f9811b307e] -- add your button handler code here.. - showExporterMenu(); - //[/UserButtonCode_c1f6e5f9811b307e] - } else if (buttonThatWasClicked == &saveAndOpenButton) { //[UserButtonCode_dRGMyYx] -- add your button handler code here.. @@ -595,120 +897,9 @@ void ProjectInformationComponent::paint (Graphics& g) //[MiscUserCode] You can add your own definitions of your custom methods or any other code here... -void ProjectInformationComponent::rebuildConfigTabs() -{ - configTabBox.clearTabs(); - - configTabBox.addTab ("Project Settings", Colours::lightslategrey, new ProjectTab (project), true, -1); - configTabBox.addTab ("Modules", Colours::lightblue, new ModulesPanel (project), true, -1); - - int i; - for (i = 0; i < project.getNumConfigurations(); ++i) - { - Component* panel = new ConfigTab (project, i); - Project::BuildConfiguration config (project.getConfiguration (i)); - configTabBox.addTab (config.getName().toString(), Colour::greyLevel (0.65f), panel, true, -1); - } - - for (i = 0; i < project.getNumExporters(); ++i) - { - ScopedPointer exp (project.createExporter (i)); - - if (exp != nullptr) - { - Component* panel = new ExportTab (project, i); - configTabBox.addTab (exp->getName(), Colours::lightsteelblue, panel, true, -1); - } - } - - lastProjectType = project.getProjectTypeValue().getValue(); -} - -void ProjectInformationComponent::updateConfigTabs() -{ - if (configTabBox.getNumTabs() != project.getNumConfigurations() + project.getNumExporters() + 2 - || lastProjectType != project.getProjectTypeValue().getValue()) - { - rebuildConfigTabs(); - } - else - { - for (int i = 0; i < project.getNumConfigurations(); ++i) - { - Project::BuildConfiguration config (project.getConfiguration (i)); - configTabBox.setTabName (i + 2, config.getName().toString()); - } - } -} - -void ProjectInformationComponent::showConfigMenu() -{ - PopupMenu m; - m.addItem (1, "Add a new empty configuration"); - - PopupMenu createCopyMenu, removeMenu; - - for (int i = 0; i < project.getNumConfigurations(); ++i) - { - Project::BuildConfiguration config (project.getConfiguration (i)); - createCopyMenu.addItem (i + 10000, "Create a copy of '" + config.getName().toString() + "'"); - removeMenu.addItem (i + 20000, "Delete configuration '" + config.getName().toString() + "'"); - } - - m.addSubMenu ("Add a copy of an existing configuration", createCopyMenu); - m.addSubMenu ("Remove configuration", removeMenu); - - const int r = m.showAt (&editConfigsButton); - - if (r >= 20000) - { - project.deleteConfiguration (r - 20000); - } - else if (r >= 10000) - { - Project::BuildConfiguration configToCopy (project.getConfiguration (r - 10000)); - project.addNewConfiguration (&configToCopy); - } - else if (r == 1) - { - project.addNewConfiguration (nullptr); - } -} - -void ProjectInformationComponent::showExporterMenu() -{ - PopupMenu m; - - PopupMenu createMenu, removeMenu; - - int i; - for (i = 0; i < project.getNumExporters(); ++i) - { - ScopedPointer exp (project.createExporter (i)); - - if (exp != nullptr) - removeMenu.addItem (i + 20000, "Delete " + exp->getName()); - } - - StringArray exporters (ProjectExporter::getExporterNames()); - - for (i = 0; i < exporters.size(); ++i) - createMenu.addItem (i + 10000, "Create a new " + exporters[i] + " target"); - - m.addSubMenu ("Create new export target", createMenu); - m.addSubMenu ("Remove export target", removeMenu); - - const int r = m.showAt (&editExportersButton); - - if (r >= 20000) - project.deleteExporter (r - 20000); - else if (r >= 10000) - project.addNewExporter (exporters [r - 10000]); -} - void ProjectInformationComponent::changeListenerCallback (ChangeBroadcaster*) { - updateConfigTabs(); + dynamic_cast (viewport.getViewedComponent())->update(); } //[/MiscUserCode] @@ -718,33 +909,25 @@ void ProjectInformationComponent::changeListenerCallback (ChangeBroadcaster*) //======================= Jucer Information Section ========================== //============================================================================== #if 0 -/* This section stores the Jucer's metadata - edit it at your own risk! +/* This section stores the metadata for this component - edit it at your own risk! JUCER_COMPONENT_METADATA_START - - - + - - + + connectedRight="0" connectedTop="0" connectedBottom="0" backgroundColour="FFDDDDFF"/> + diff --git a/extras/Introjucer/Source/Project/jucer_ProjectInformationComponent.h b/extras/Introjucer/Source/Project/jucer_ProjectInformationComponent.h index 823e370b79..8dffc98b05 100644 --- a/extras/Introjucer/Source/Project/jucer_ProjectInformationComponent.h +++ b/extras/Introjucer/Source/Project/jucer_ProjectInformationComponent.h @@ -1,23 +1,23 @@ /* ============================================================================== - This is an automatically generated file created by the Jucer! + This is an automatically generated file! Be careful when adding custom code to these files, as only the code within the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded and re-saved. - Created for JUCE version: JUCE v1.53.8 + Created for JUCE version: JUCE v2.0.9 ------------------------------------------------------------------------------ - JUCE and the Jucer are copyright 2004-10 by Raw Material Software ltd. + JUCE is copyright 2004-11 by Raw Material Software ltd. ============================================================================== */ -#ifndef __JUCER_PROJECTINFORMATIONCOMPONENT_H_2F89B0AC__ -#define __JUCER_PROJECTINFORMATIONCOMPONENT_H_2F89B0AC__ +#ifndef __JUCER_PROJECTINFORMATIONCOMPONENT_H_30FFCD07__ +#define __JUCER_PROJECTINFORMATIONCOMPONENT_H_30FFCD07__ //[Headers] -- You can add your own extra header files here -- #include "jucer_Project.h" @@ -33,7 +33,7 @@ */ class ProjectInformationComponent : public Component, public ChangeListener, - public ButtonListener + public Button::Listener { public: //============================================================================== @@ -43,7 +43,6 @@ public: //============================================================================== //[UserMethods] -- You can add your own custom methods in this section. void changeListenerCallback (ChangeBroadcaster*); - void rebuildConfigTabs(); //[/UserMethods] void resized(); @@ -51,27 +50,24 @@ public: void paint (Graphics& g); + private: //============================================================================== //[UserVariables] -- You can add your own custom variables in this section. Project& project; - - var lastProjectType; - void updateConfigTabs(); - void showConfigMenu(); - void showExporterMenu(); + class RolloverHelpComp; //[/UserVariables] //============================================================================== - TabbedComponent configTabBox; - TextButton editConfigsButton; + Viewport viewport; TextButton openProjectButton; - TextButton editExportersButton; TextButton saveAndOpenButton; + ScopedPointer rollover; + //============================================================================== JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ProjectInformationComponent); }; -#endif // __JUCER_PROJECTINFORMATIONCOMPONENT_H_2F89B0AC__ +#endif // __JUCER_PROJECTINFORMATIONCOMPONENT_H_30FFCD07__ diff --git a/modules/juce_graphics/geometry/juce_RectangleList.cpp b/modules/juce_graphics/geometry/juce_RectangleList.cpp index e969e0cc5a..61d2708d85 100644 --- a/modules/juce_graphics/geometry/juce_RectangleList.cpp +++ b/modules/juce_graphics/geometry/juce_RectangleList.cpp @@ -32,8 +32,7 @@ RectangleList::RectangleList() noexcept RectangleList::RectangleList (const Rectangle& rect) { - if (! rect.isEmpty()) - rects.add (rect); + addWithoutMerging (rect); } RectangleList::RectangleList (const RectangleList& other) @@ -99,7 +98,7 @@ bool RectangleList::Iterator::next() noexcept { if (--index >= 0) { - current = & (owner.rects.getReference (index)); + current = &(owner.rects.getReference (index)); return true; } @@ -120,15 +119,14 @@ void RectangleList::add (const Rectangle& rect) { bool anyOverlaps = false; - int i; - for (i = rects.size(); --i >= 0;) + for (int j = rects.size(); --j >= 0;) { - Rectangle& ourRect = rects.getReference (i); + Rectangle& ourRect = rects.getReference (j); if (rect.intersects (ourRect)) { if (rect.contains (ourRect)) - rects.remove (i); + rects.remove (j); else if (! ourRect.reduceIfPartlyContainedIn (rect)) anyOverlaps = true; } @@ -138,7 +136,7 @@ void RectangleList::add (const Rectangle& rect) { RectangleList r (rect); - for (i = rects.size(); --i >= 0;) + for (int i = rects.size(); --i >= 0;) { const Rectangle& ourRect = rects.getReference (i); @@ -151,8 +149,7 @@ void RectangleList::add (const Rectangle& rect) } } - for (i = r.getNumRectangles(); --i >= 0;) - rects.add (r.rects.getReference (i)); + rects.addArray (r.rects); } else { @@ -170,15 +167,7 @@ void RectangleList::addWithoutMerging (const Rectangle& rect) void RectangleList::add (const int x, const int y, const int w, const int h) { - if (rects.size() == 0) - { - if (w > 0 && h > 0) - rects.add (Rectangle (x, y, w, h)); - } - else - { - add (Rectangle (x, y, w, h)); - } + add (Rectangle (x, y, w, h)); } void RectangleList::add (const RectangleList& other) @@ -220,8 +209,8 @@ void RectangleList::subtract (const Rectangle& rect) r.x = x1; r.w = rx2 - x1; - rects.insert (i + 1, Rectangle (rx1, ry1, x1 - rx1, ry2 - ry1)); - i += 2; + rects.insert (++i, Rectangle (rx1, ry1, x1 - rx1, ry2 - ry1)); + ++i; } } else if (x2 > rx1 && x2 < rx2) @@ -231,8 +220,8 @@ void RectangleList::subtract (const Rectangle& rect) if (y1 > ry1 || y2 < ry2 || x1 > rx1) { - rects.insert (i + 1, Rectangle (rx1, ry1, x2 - rx1, ry2 - ry1)); - i += 2; + rects.insert (++i, Rectangle (rx1, ry1, x2 - rx1, ry2 - ry1)); + ++i; } } else if (y1 > ry1 && y1 < ry2) @@ -246,8 +235,8 @@ void RectangleList::subtract (const Rectangle& rect) r.y = y1; r.h = ry2 - y1; - rects.insert (i + 1, Rectangle (rx1, ry1, rx2 - rx1, y1 - ry1)); - i += 2; + rects.insert (++i, Rectangle (rx1, ry1, rx2 - rx1, y1 - ry1)); + ++i; } } else if (y2 > ry1 && y2 < ry2) @@ -257,8 +246,8 @@ void RectangleList::subtract (const Rectangle& rect) if (x1 > rx1 || x2 < rx2 || y1 > ry1) { - rects.insert (i + 1, Rectangle (rx1, ry1, rx2 - rx1, y2 - ry1)); - i += 2; + rects.insert (++i, Rectangle (rx1, ry1, rx2 - rx1, y2 - ry1)); + ++i; } } else @@ -522,15 +511,8 @@ Path RectangleList::toPath() const { Path p; - for (int i = rects.size(); --i >= 0;) - { - const Rectangle& r = rects.getReference (i); - - p.addRectangle ((float) r.x, - (float) r.y, - (float) r.w, - (float) r.h); - } + for (int i = 0; i < rects.size(); ++i) + p.addRectangle (rects.getReference (i)); return p; } diff --git a/modules/juce_gui_basics/layout/juce_Viewport.cpp b/modules/juce_gui_basics/layout/juce_Viewport.cpp index e87b9b46ff..7edd16eb4b 100644 --- a/modules/juce_gui_basics/layout/juce_Viewport.cpp +++ b/modules/juce_gui_basics/layout/juce_Viewport.cpp @@ -68,7 +68,6 @@ void Viewport::deleteContentComp() // This sets the content comp to a null pointer before deleting the old one, in case // anything tries to use the old one while it's in mid-deletion.. ScopedPointer oldCompDeleter (contentComp); - contentComp = nullptr; } else { @@ -186,37 +185,50 @@ void Viewport::updateVisibleArea() const bool canShowHBar = showHScrollbar && canShowAnyBars; const bool canShowVBar = showVScrollbar && canShowAnyBars; - bool hBarVisible = canShowHBar && ! horizontalScrollBar.autoHides(); - bool vBarVisible = canShowVBar && ! verticalScrollBar.autoHides(); + bool hBarVisible, vBarVisible; + Rectangle contentArea; - Rectangle contentArea (getLocalBounds()); - - if (contentComp != nullptr && ! contentArea.contains (contentComp->getBounds())) + for (int i = 3; --i >= 0;) { - hBarVisible = canShowHBar && (hBarVisible || contentComp->getX() < 0 || contentComp->getRight() > contentArea.getWidth()); - vBarVisible = canShowVBar && (vBarVisible || contentComp->getY() < 0 || contentComp->getBottom() > contentArea.getHeight()); + hBarVisible = canShowHBar && ! horizontalScrollBar.autoHides(); + vBarVisible = canShowVBar && ! verticalScrollBar.autoHides(); + contentArea = getLocalBounds(); - if (vBarVisible) - contentArea.setWidth (getWidth() - scrollbarWidth); - - if (hBarVisible) - contentArea.setHeight (getHeight() - scrollbarWidth); - - if (! contentArea.contains (contentComp->getBounds())) + if (contentComp != nullptr && ! contentArea.contains (contentComp->getBounds())) { - hBarVisible = canShowHBar && (hBarVisible || contentComp->getRight() > contentArea.getWidth()); - vBarVisible = canShowVBar && (vBarVisible || contentComp->getBottom() > contentArea.getHeight()); + hBarVisible = canShowHBar && (hBarVisible || contentComp->getX() < 0 || contentComp->getRight() > contentArea.getWidth()); + vBarVisible = canShowVBar && (vBarVisible || contentComp->getY() < 0 || contentComp->getBottom() > contentArea.getHeight()); + + if (vBarVisible) + contentArea.setWidth (getWidth() - scrollbarWidth); + + if (hBarVisible) + contentArea.setHeight (getHeight() - scrollbarWidth); + + if (! contentArea.contains (contentComp->getBounds())) + { + hBarVisible = canShowHBar && (hBarVisible || contentComp->getRight() > contentArea.getWidth()); + vBarVisible = canShowVBar && (vBarVisible || contentComp->getBottom() > contentArea.getHeight()); + } } + + if (vBarVisible) contentArea.setWidth (getWidth() - scrollbarWidth); + if (hBarVisible) contentArea.setHeight (getHeight() - scrollbarWidth); + + if (contentComp == nullptr) + { + contentHolder.setBounds (contentArea); + break; + } + + const Rectangle oldContentBounds (contentComp->getBounds()); + contentHolder.setBounds (contentArea); + + // If the content has changed its size, that might affect our scrollbars, so go round again and re-caclulate.. + if (oldContentBounds == contentComp->getBounds()) + break; } - if (vBarVisible) - contentArea.setWidth (getWidth() - scrollbarWidth); - - if (hBarVisible) - contentArea.setHeight (getHeight() - scrollbarWidth); - - contentHolder.setBounds (contentArea); - Rectangle contentBounds; if (contentComp != nullptr) contentBounds = contentHolder.getLocalArea (contentComp, contentComp->getLocalBounds()); diff --git a/modules/juce_gui_basics/positioning/juce_RelativeRectangle.cpp b/modules/juce_gui_basics/positioning/juce_RelativeRectangle.cpp index 71c7e439fb..6b0f7d1614 100644 --- a/modules/juce_gui_basics/positioning/juce_RelativeRectangle.cpp +++ b/modules/juce_gui_basics/positioning/juce_RelativeRectangle.cpp @@ -223,7 +223,7 @@ public: getComponent().setBounds (newBounds); } - jassertfalse; // must be a recursive reference! + jassertfalse; // Seems to be a recursive reference! } void applyNewBounds (const Rectangle& newBounds) diff --git a/modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.cpp b/modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.cpp index 5b644250ff..510037b338 100644 --- a/modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.cpp +++ b/modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.cpp @@ -611,7 +611,7 @@ public: void setColour (const float alpha) noexcept { - const uint8 v = jmin (255, (int) (alpha * 255.0f)); + const uint8 v = (uint8) jmin (255, (int) (alpha * 255.0f)); setColour (PixelARGB (v, v, v, v)); } @@ -727,7 +727,7 @@ public: { GLint t = 0; glGetIntegerv (GL_TEXTURE_BINDING_2D, &t); - jassert (t == textureID); + jassert (t == (GLint) textureID); } }