diff --git a/extras/Introjucer/Source/Application/jucer_Application.h b/extras/Introjucer/Source/Application/jucer_Application.h index 0ad33cda59..9e351a1163 100644 --- a/extras/Introjucer/Source/Application/jucer_Application.h +++ b/extras/Introjucer/Source/Application/jucer_Application.h @@ -74,7 +74,7 @@ public: { CodeDocument doc; - CodeEditorComponent ed (doc, nullptr); + CppCodeEditorComponent ed (File::nonexistent, doc); commandManager->registerAllCommandsForTarget (&ed); } diff --git a/extras/Introjucer/Source/Application/jucer_MainWindow.cpp b/extras/Introjucer/Source/Application/jucer_MainWindow.cpp index b4035d91b5..da1a559133 100644 --- a/extras/Introjucer/Source/Application/jucer_MainWindow.cpp +++ b/extras/Introjucer/Source/Application/jucer_MainWindow.cpp @@ -71,6 +71,8 @@ MainWindow::MainWindow() //getPeer()->setCurrentRenderingEngine (0); getLookAndFeel().setColour (ColourSelector::backgroundColourId, Colours::transparentBlack); + + setResizeLimits (600, 500, 32000, 32000); } MainWindow::~MainWindow() diff --git a/extras/Introjucer/Source/Code Editor/jucer_SourceCodeEditor.cpp b/extras/Introjucer/Source/Code Editor/jucer_SourceCodeEditor.cpp index 6933ff7e57..6eafd57951 100644 --- a/extras/Introjucer/Source/Code Editor/jucer_SourceCodeEditor.cpp +++ b/extras/Introjucer/Source/Code Editor/jucer_SourceCodeEditor.cpp @@ -27,8 +27,8 @@ #include "../Application/jucer_OpenDocumentManager.h" //============================================================================== -SourceCodeDocument::SourceCodeDocument (Project* project_, const File& file_) - : modDetector (file_), project (project_) +SourceCodeDocument::SourceCodeDocument (Project* p, const File& f) + : modDetector (f), project (p) { } @@ -97,8 +97,8 @@ void SourceCodeDocument::applyLastState (CodeEditorComponent& editor) const } //============================================================================== -SourceCodeEditor::SourceCodeEditor (OpenDocumentManager::Document* document_) - : DocumentEditorComponent (document_) +SourceCodeEditor::SourceCodeEditor (OpenDocumentManager::Document* doc) + : DocumentEditorComponent (doc) { } @@ -177,6 +177,10 @@ CppCodeEditorComponent::CppCodeEditorComponent (const File& f, CodeDocument& cod setCommandManager (commandManager); } +CppCodeEditorComponent::~CppCodeEditorComponent() +{ +} + void CppCodeEditorComponent::handleReturnKey() { CodeEditorComponent::handleReturnKey(); @@ -260,3 +264,265 @@ void CppCodeEditorComponent::performPopupMenuAction (int menuItemID) else CodeEditorComponent::performPopupMenuAction (menuItemID); } + +void CppCodeEditorComponent::getAllCommands (Array & commands) +{ + CodeEditorComponent::getAllCommands (commands); + + const CommandID ids[] = { CommandIDs::showFindPanel, + CommandIDs::findSelection, + CommandIDs::findNext, + CommandIDs::findPrevious }; + + commands.addArray (ids, numElementsInArray (ids)); +} + +void CppCodeEditorComponent::getCommandInfo (const CommandID commandID, ApplicationCommandInfo& result) +{ + const bool anythingSelected = isHighlightActive(); + + switch (commandID) + { + case CommandIDs::showFindPanel: + result.setInfo (TRANS ("Find"), TRANS ("Searches for text in the current document."), "Editing", 0); + result.defaultKeypresses.add (KeyPress ('f', ModifierKeys::commandModifier, 0)); + break; + + case CommandIDs::findSelection: + result.setInfo (TRANS ("Find Selection"), TRANS ("Searches for the currently selected text."), "Editing", 0); + result.setActive (anythingSelected); + result.defaultKeypresses.add (KeyPress ('l', ModifierKeys::commandModifier, 0)); + break; + + case CommandIDs::findNext: + result.setInfo (TRANS ("Find Next"), TRANS ("Searches for the next occurrence of the current search-term."), "Editing", 0); + result.defaultKeypresses.add (KeyPress ('g', ModifierKeys::commandModifier, 0)); + break; + + case CommandIDs::findPrevious: + result.setInfo (TRANS ("Find Previous"), TRANS ("Searches for the previous occurrence of the current search-term."), "Editing", 0); + result.defaultKeypresses.add (KeyPress ('g', ModifierKeys::commandModifier | ModifierKeys::shiftModifier, 0)); + result.defaultKeypresses.add (KeyPress ('d', ModifierKeys::commandModifier, 0)); + break; + + default: + CodeEditorComponent::getCommandInfo (commandID, result); + break; + } +} + +bool CppCodeEditorComponent::perform (const InvocationInfo& info) +{ + switch (info.commandID) + { + case CommandIDs::showFindPanel: showFindPanel(); return true; + case CommandIDs::findSelection: findSelection(); return true; + case CommandIDs::findNext: findNext (true, true); return true; + case CommandIDs::findPrevious: findNext (false, false); return true; + default: break; + } + + return CodeEditorComponent::perform (info); +} + +//============================================================================== +class CppCodeEditorComponent::FindPanel : public Component, + private TextEditor::Listener, + private Button::Listener +{ +public: + FindPanel() + : caseButton ("Case-sensitive"), + findPrev ("<"), + findNext (">") + { + editor.setColour (CaretComponent::caretColourId, Colours::black); + + addAndMakeVisible (&editor); + label.setText ("Find:", false); + label.setColour (Label::textColourId, Colours::white); + label.attachToComponent (&editor, false); + + addAndMakeVisible (&caseButton); + caseButton.setColour (ToggleButton::textColourId, Colours::white); + caseButton.setToggleState (isCaseSensitiveSearch(), false); + caseButton.addListener (this); + + findPrev.setConnectedEdges (Button::ConnectedOnRight); + findNext.setConnectedEdges (Button::ConnectedOnLeft); + addAndMakeVisible (&findPrev); + addAndMakeVisible (&findNext); + + setWantsKeyboardFocus (false); + setFocusContainer (true); + findPrev.setWantsKeyboardFocus (false); + findNext.setWantsKeyboardFocus (false); + + editor.setText (getSearchString()); + editor.addListener (this); + } + + void setCommandManager (ApplicationCommandManager* cm) + { + findPrev.setCommandToTrigger (cm, CommandIDs::findPrevious, true); + findNext.setCommandToTrigger (cm, CommandIDs::findNext, true); + } + + void paint (Graphics& g) + { + Path outline; + outline.addRoundedRectangle (1.0f, 1.0f, getWidth() - 2.0f, getHeight() - 2.0f, 8.0f); + + g.setColour (Colours::black.withAlpha (0.6f)); + g.fillPath (outline); + g.setColour (Colours::white.withAlpha (0.8f)); + g.strokePath (outline, PathStrokeType (1.0f)); + } + + void resized() + { + int y = 30; + editor.setBounds (10, y, getWidth() - 20, 24); + y += 30; + caseButton.setBounds (10, y, getWidth() / 2 - 10, 22); + findNext.setBounds (getWidth() - 40, y, 30, 22); + findPrev.setBounds (getWidth() - 70, y, 30, 22); + } + + void buttonClicked (Button*) + { + setCaseSensitiveSearch (caseButton.getToggleState()); + } + + void textEditorTextChanged (TextEditor&) + { + setSearchString (editor.getText()); + + if (CppCodeEditorComponent* ed = getOwner()) + ed->findNext (true, false); + } + + void textEditorFocusLost (TextEditor&) {} + + void textEditorReturnKeyPressed (TextEditor&) + { + commandManager->invokeDirectly (CommandIDs::findNext, true); + } + + void textEditorEscapeKeyPressed (TextEditor&) + { + if (CppCodeEditorComponent* ed = getOwner()) + ed->hideFindPanel(); + } + + CppCodeEditorComponent* getOwner() const + { + return findParentComponentOfClass (); + } + + TextEditor editor; + Label label; + ToggleButton caseButton; + TextButton findPrev, findNext; +}; + +void CppCodeEditorComponent::showFindPanel() +{ + if (findPanel == nullptr) + { + findPanel = new FindPanel(); + findPanel->setCommandManager (commandManager); + + addAndMakeVisible (findPanel); + resized(); + } + + findPanel->editor.grabKeyboardFocus(); + findPanel->editor.selectAll(); +} + +void CppCodeEditorComponent::hideFindPanel() +{ + findPanel = nullptr; +} + +void CppCodeEditorComponent::findSelection() +{ + const String selected (getTextInRange (getHighlightedRegion())); + + if (selected.isNotEmpty()) + { + setSearchString (selected); + findNext (true, true); + } +} + +void CppCodeEditorComponent::findNext (bool forwards, bool skipCurrentSelection) +{ + const Range highlight (getHighlightedRegion()); + const CodeDocument::Position startPos (getDocument(), skipCurrentSelection ? highlight.getEnd() + : highlight.getStart()); + int lineNum = startPos.getLineNumber(); + int linePos = startPos.getIndexInLine(); + + const int totalLines = getDocument().getNumLines(); + const String searchText (getSearchString()); + const bool caseSensitive = isCaseSensitiveSearch(); + + for (int linesToSearch = totalLines; --linesToSearch >= 0;) + { + String line (getDocument().getLine (lineNum)); + int index; + + if (forwards) + { + index = caseSensitive ? line.indexOf (linePos, searchText) + : line.indexOfIgnoreCase (linePos, searchText); + } + else + { + if (linePos >= 0) + line = line.substring (0, linePos); + + index = caseSensitive ? line.lastIndexOf (searchText) + : line.lastIndexOfIgnoreCase (searchText); + } + + if (index >= 0) + { + const CodeDocument::Position p (getDocument(), lineNum, index); + selectRegion (p, p.movedBy (searchText.length())); + break; + } + + if (forwards) + { + linePos = 0; + lineNum = (lineNum + 1) % totalLines; + } + else + { + if (--lineNum < 0) + lineNum = totalLines - 1; + + linePos = -1; + } + } +} + +void CppCodeEditorComponent::handleEscapeKey() +{ + CodeEditorComponent::handleEscapeKey(); + hideFindPanel(); +} + +void CppCodeEditorComponent::resized() +{ + CodeEditorComponent::resized(); + + if (findPanel != nullptr) + { + findPanel->setSize (jmin (260, getWidth() - 32), 100); + findPanel->setTopRightPosition (getWidth() - 16, 8); + } +} diff --git a/extras/Introjucer/Source/Code Editor/jucer_SourceCodeEditor.h b/extras/Introjucer/Source/Code Editor/jucer_SourceCodeEditor.h index 81bb8bc13d..f07d266a8c 100644 --- a/extras/Introjucer/Source/Code Editor/jucer_SourceCodeEditor.h +++ b/extras/Introjucer/Source/Code Editor/jucer_SourceCodeEditor.h @@ -169,15 +169,36 @@ class CppCodeEditorComponent : public CodeEditorComponent { public: CppCodeEditorComponent (const File& file, CodeDocument& codeDocument); + ~CppCodeEditorComponent(); void handleReturnKey(); + void handleEscapeKey(); void insertTextAtCaret (const String& newText); void addPopupMenuItems (PopupMenu&, const MouseEvent*); void performPopupMenuAction (int menuItemID); + void getAllCommands (Array&); + void getCommandInfo (CommandID, ApplicationCommandInfo&); + bool perform (const InvocationInfo&); + + void showFindPanel(); + void hideFindPanel(); + void findSelection(); + void findNext (bool forwards, bool skipCurrentSelection); + + void resized(); + + static String getSearchString() { return getAppSettings().getGlobalProperties().getValue ("searchString"); } + static void setSearchString (const String& s) { getAppSettings().getGlobalProperties().setValue ("searchString", s); } + static bool isCaseSensitiveSearch() { return getAppSettings().getGlobalProperties().getBoolValue ("searchCaseSensitive"); } + static void setCaseSensitiveSearch (bool b) { getAppSettings().getGlobalProperties().setValue ("searchCaseSensitive", b); } + private: File file; + class FindPanel; + ScopedPointer findPanel; + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CppCodeEditorComponent); }; diff --git a/extras/Introjucer/Source/Project/jucer_ProjectContentComponent.cpp b/extras/Introjucer/Source/Project/jucer_ProjectContentComponent.cpp index 7b55e53cce..05dd7c648f 100644 --- a/extras/Introjucer/Source/Project/jucer_ProjectContentComponent.cpp +++ b/extras/Introjucer/Source/Project/jucer_ProjectContentComponent.cpp @@ -636,7 +636,7 @@ void ProjectContentComponent::getCommandInfo (const CommandID commandID, Applica "Saves the project and launches it in an external IDE", CommandCategories::general, 0); result.setActive (ProjectExporter::canProjectBeLaunched (project)); - result.defaultKeypresses.add (KeyPress ('l', ModifierKeys::commandModifier, 0)); + result.defaultKeypresses.add (KeyPress ('l', ModifierKeys::commandModifier | ModifierKeys::shiftModifier, 0)); break; case CommandIDs::showFilePanel: diff --git a/modules/juce_gui_basics/keyboard/juce_CaretComponent.cpp b/modules/juce_gui_basics/keyboard/juce_CaretComponent.cpp index e6bdde39ca..26c0faec84 100644 --- a/modules/juce_gui_basics/keyboard/juce_CaretComponent.cpp +++ b/modules/juce_gui_basics/keyboard/juce_CaretComponent.cpp @@ -52,6 +52,6 @@ void CaretComponent::setCaretPosition (const Rectangle& characterArea) bool CaretComponent::shouldBeShown() const { - return owner == nullptr || (owner->hasKeyboardFocus (true) + return owner == nullptr || (owner->hasKeyboardFocus (false) && ! owner->isCurrentlyBlockedByAnotherModalComponent()); }