diff --git a/TODO.md b/TODO.md index fb7b8ab22..ab9784618 100644 --- a/TODO.md +++ b/TODO.md @@ -1,10 +1,22 @@ # TODO - Short and mid term plans. +# Log + +* Add log levels. + +# CSS transitions and animations + +* Add `cubic-bezier` timing function support. + ## UICodeEditor * Add new CSS properties related to the widget. +## StyleSheetParser + +Detect errors and log them. + ## TextDocument * Add multi-line search and replace. @@ -13,10 +25,6 @@ * Add XML tags auto-close. -## StyleSheetParser - -Detect errors and log them. - ## UITreeView Implement a simple tree view widget, to at least cover the most common use cases. @@ -29,16 +37,10 @@ Implement a simple tree view widget, to at least cover the most common use cases * Add support for function listing. -* Change pixel density from the UI. - -* Display current line-collumn and document line count. +* Display number of results in search and number of replacements. ## UI Editor * Integrate the `UICodeEditor` into the editor in order to be able to edit the layouts and CSS in app. * Once `UITreeView` is finished add a tree view inspector of the node tree. - -# Log - -* Add log levels. diff --git a/include/eepp/ui/tools/uicodeeditorsplitter.hpp b/include/eepp/ui/tools/uicodeeditorsplitter.hpp index 5aade26e5..289e7e390 100644 --- a/include/eepp/ui/tools/uicodeeditorsplitter.hpp +++ b/include/eepp/ui/tools/uicodeeditorsplitter.hpp @@ -32,6 +32,8 @@ class EE_API UICodeEditorSplitter { virtual void onDocumentSelectionChange( UICodeEditor* editor, TextDocument& doc ) = 0; + virtual void onDocumentCursorPosChange( UICodeEditor* editor, TextDocument& doc ) = 0; + virtual void onColorSchemeChanged( const std::string& currentColorScheme ) = 0; virtual void onDocumentLoaded( UICodeEditor* codeEditor, const std::string& path ) = 0; diff --git a/include/eepp/ui/uicodeeditor.hpp b/include/eepp/ui/uicodeeditor.hpp index 6d37d9c91..9567a6835 100644 --- a/include/eepp/ui/uicodeeditor.hpp +++ b/include/eepp/ui/uicodeeditor.hpp @@ -533,6 +533,8 @@ class EE_API UICodeEditor : public UIWidget, public TextDocument::Client { virtual void onFontChanged(); + virtual void onFontStyleChanged(); + virtual void onDocumentChanged(); virtual Uint32 onMessage( const NodeMessage* msg ); diff --git a/include/eepp/ui/uitextedit.hpp b/include/eepp/ui/uitextedit.hpp index b71875e3a..7e95376a9 100644 --- a/include/eepp/ui/uitextedit.hpp +++ b/include/eepp/ui/uitextedit.hpp @@ -44,6 +44,8 @@ class EE_API UITextEdit : public UICodeEditor { virtual void onFontChanged(); + virtual void onFontStyleChanged(); + virtual void onDocumentLineChanged( const Int64& lineIndex ); virtual void drawLineText( const Int64& index, Vector2f position, const Float& fontSize, diff --git a/src/eepp/ui/doc/syntaxdefinitionmanager.cpp b/src/eepp/ui/doc/syntaxdefinitionmanager.cpp index 2e984991d..ed88624cd 100644 --- a/src/eepp/ui/doc/syntaxdefinitionmanager.cpp +++ b/src/eepp/ui/doc/syntaxdefinitionmanager.cpp @@ -892,7 +892,8 @@ SyntaxDefinitionManager::SyntaxDefinitionManager() { {{"https?://%S+"}, "link"}, }, {}, - "#"} ); + "#", + {"^%[.-%]"}} ); // Makefile add( {"Makefile", diff --git a/src/eepp/ui/doc/textdocument.cpp b/src/eepp/ui/doc/textdocument.cpp index a96cd9cdc..d5be7d5de 100644 --- a/src/eepp/ui/doc/textdocument.cpp +++ b/src/eepp/ui/doc/textdocument.cpp @@ -504,9 +504,10 @@ void TextDocument::remove( TextRange range, UndoStackContainer& undoStack, const mUndoStack.pushInsert( undoStack, getText( range ), range.start(), time ); // First delete all the lines in between the first and last one. - for ( auto i = range.start().line() + 1; i < range.end().line(); ) { - mLines.erase( mLines.begin() + i ); - range.end().setLine( range.end().line() - 1 ); + if ( range.start().line() + 1 < range.end().line() ) { + mLines.erase( mLines.begin() + range.start().line() + 1, + mLines.begin() + range.end().line() ); + range.end().setLine( range.start().line() + 1 ); } if ( range.start().line() == range.end().line() ) { diff --git a/src/eepp/ui/tools/uicodeeditorsplitter.cpp b/src/eepp/ui/tools/uicodeeditorsplitter.cpp index a3c71d7b7..d91ceb344 100644 --- a/src/eepp/ui/tools/uicodeeditorsplitter.cpp +++ b/src/eepp/ui/tools/uicodeeditorsplitter.cpp @@ -243,7 +243,11 @@ UICodeEditor* UICodeEditorSplitter::createCodeEditor() { event->getNode()->asType(), event->getNode()->asType()->getDocument() ); } ); - + editor->addEventListener( Event::OnCursorPosChange, [&]( const Event* event ) { + mClient->onDocumentCursorPosChange( + event->getNode()->asType(), + event->getNode()->asType()->getDocument() ); + } ); editor->addKeyBinds( getLocalDefaultKeybindings() ); editor->addUnlockedCommands( {"lock-toggle", "create-new", "close-doc", "next-doc", "previous-doc", "split-left", diff --git a/src/eepp/ui/uicodeeditor.cpp b/src/eepp/ui/uicodeeditor.cpp index 7a76bd855..1d4a3b782 100644 --- a/src/eepp/ui/uicodeeditor.cpp +++ b/src/eepp/ui/uicodeeditor.cpp @@ -366,6 +366,8 @@ UICodeEditor* UICodeEditor::setFont( Font* font ) { void UICodeEditor::onFontChanged() {} +void UICodeEditor::onFontStyleChanged() {} + void UICodeEditor::onDocumentChanged() { DocEvent event( this, mDoc.get(), Event::OnDocumentChanged ); sendEvent( &event ); @@ -415,6 +417,7 @@ UICodeEditor* UICodeEditor::setFontColor( const Color& color ) { if ( mFontStyleConfig.getFontColor() != color ) { mFontStyleConfig.FontColor = color; invalidateDraw(); + onFontStyleChanged(); } return this; } @@ -431,6 +434,7 @@ UICodeEditor* UICodeEditor::setFontSelectedColor( const Color& color ) { if ( mFontStyleConfig.getFontSelectedColor() != color ) { mFontStyleConfig.FontSelectedColor = color; invalidateDraw(); + onFontStyleChanged(); } return this; } @@ -439,6 +443,7 @@ UICodeEditor* UICodeEditor::setFontSelectionBackColor( const Color& color ) { if ( mFontStyleConfig.getFontSelectionBackColor() != color ) { mFontStyleConfig.FontSelectionBackColor = color; invalidateDraw(); + onFontStyleChanged(); } return this; } @@ -1202,6 +1207,7 @@ UICodeEditor* UICodeEditor::setFontShadowColor( const Color& color ) { if ( mFontStyleConfig.ShadowColor != color ) { mFontStyleConfig.ShadowColor = color; invalidateDraw(); + onFontStyleChanged(); } return this; @@ -1211,6 +1217,7 @@ UICodeEditor* UICodeEditor::setFontStyle( const Uint32& fontStyle ) { if ( mFontStyleConfig.Style != fontStyle ) { mFontStyleConfig.Style = fontStyle; invalidateDraw(); + onFontStyleChanged(); } return this; @@ -1232,6 +1239,7 @@ UICodeEditor* UICodeEditor::setOutlineThickness( const Float& outlineThickness ) if ( mFontStyleConfig.OutlineThickness != outlineThickness ) { mFontStyleConfig.OutlineThickness = outlineThickness; invalidateDraw(); + onFontStyleChanged(); } return this; @@ -1245,6 +1253,7 @@ UICodeEditor* UICodeEditor::setOutlineColor( const Color& outlineColor ) { if ( mFontStyleConfig.OutlineColor != outlineColor ) { mFontStyleConfig.OutlineColor = outlineColor; invalidateDraw(); + onFontStyleChanged(); } return this; diff --git a/src/eepp/ui/uilinearlayout.cpp b/src/eepp/ui/uilinearlayout.cpp index 7ce2c141e..82873da02 100644 --- a/src/eepp/ui/uilinearlayout.cpp +++ b/src/eepp/ui/uilinearlayout.cpp @@ -201,6 +201,8 @@ void UILinearLayout::packVertical() { child = child->getNextNode(); } + maxX += mPadding.Left + mPadding.Right; + if ( getLayoutHeightPolicy() == SizePolicy::WrapContent ) { curY += mPadding.Bottom; @@ -375,6 +377,8 @@ void UILinearLayout::packHorizontal() { child = child->getNextNode(); } + maxY += mPadding.Top + mPadding.Bottom; + if ( getLayoutWidthPolicy() == SizePolicy::WrapContent ) { curX += mPadding.Right; diff --git a/src/eepp/ui/uitextedit.cpp b/src/eepp/ui/uitextedit.cpp index 52be726e8..9ca62719a 100644 --- a/src/eepp/ui/uitextedit.cpp +++ b/src/eepp/ui/uitextedit.cpp @@ -95,6 +95,10 @@ void UITextEdit::onFontChanged() { } } +void UITextEdit::onFontStyleChanged() { + onFontChanged(); +} + void UITextEdit::onDocumentLineChanged( const Int64& lineIndex ) { UICodeEditor::onDocumentLineChanged( lineIndex ); updateLineCache( lineIndex ); diff --git a/src/eepp/ui/uiwindow.cpp b/src/eepp/ui/uiwindow.cpp index 5429a91e1..d616ede17 100644 --- a/src/eepp/ui/uiwindow.cpp +++ b/src/eepp/ui/uiwindow.cpp @@ -101,7 +101,8 @@ UIWindow::~UIWindow() { getUISceneNode()->windowRemove( this ); - getUISceneNode()->setFocusLastWindow( this ); + if ( isParentOf( getEventDispatcher()->getFocusNode() ) ) + getUISceneNode()->setFocusLastWindow( this ); } sendCommonEvent( Event::OnWindowClose ); diff --git a/src/tools/codeeditor/codeeditor.cpp b/src/tools/codeeditor/codeeditor.cpp index 96ea9b390..9db1dec57 100644 --- a/src/tools/codeeditor/codeeditor.cpp +++ b/src/tools/codeeditor/codeeditor.cpp @@ -283,6 +283,7 @@ void App::loadConfig() { mIni.getValueB( "editor", "color_picker_selection", true ); mConfig.editor.colorPreview = mIni.getValueB( "editor", "color_preview", true ); mConfig.editor.autoComplete = mIni.getValueB( "editor", "auto_complete", true ); + mConfig.editor.showDocInfo = mIni.getValueB( "editor", "show_doc_info", true ); } void App::saveConfig() { @@ -317,6 +318,7 @@ void App::saveConfig() { mIni.setValueB( "editor", "color_picker_selection", mConfig.editor.colorPickerSelection ); mIni.setValueB( "editor", "color_preview", mConfig.editor.colorPreview ); mIni.setValueB( "editor", "auto_complete", mConfig.editor.autoComplete ); + mIni.setValueB( "editor", "show_doc_info", mConfig.editor.showDocInfo ); mIni.writeFile(); mIniState.writeFile(); } @@ -548,6 +550,7 @@ UIMenu* App::createViewMenu() { mViewMenu = UIPopUpMenu::New(); mViewMenu->addCheckBox( "Show Line Numbers" )->setActive( mConfig.editor.showLineNumbers ); mViewMenu->addCheckBox( "Show White Space" )->setActive( mConfig.editor.showWhiteSpaces ); + mViewMenu->addCheckBox( "Show Document Info" )->setActive( mConfig.editor.showDocInfo ); mViewMenu->addCheckBox( "Highlight Matching Bracket" ) ->setActive( mConfig.editor.highlightMatchingBracket ); mViewMenu->addCheckBox( "Highlight Current Line" ) @@ -568,11 +571,12 @@ UIMenu* App::createViewMenu() { ->setActive( mConfig.editor.autoComplete ) ->setTooltipText( "Auto complete shows the completion popup as you type, so you can fill\n" "in long words by typing only a few characters." ); - mViewMenu->addSeparator(); - mViewMenu->add( "Editor Font Size", findIcon( "font-size" ) ); - mViewMenu->add( "UI Font Size", findIcon( "font-size" ) ); mViewMenu->add( "Line Breaking Column" ); mViewMenu->addSeparator(); + mViewMenu->add( "UI Scale Factor (Pixel Density)", findIcon( "pixel-density" ) ); + mViewMenu->add( "UI Font Size", findIcon( "font-size" ) ); + mViewMenu->add( "Editor Font Size", findIcon( "font-size" ) ); + mViewMenu->addSeparator(); mViewMenu->addCheckBox( "Full Screen Mode" ) ->setShortcutText( getKeybind( "fullscreen-toggle" ) ) ->setId( "fullscreen-mode" ); @@ -631,6 +635,42 @@ UIMenu* App::createViewMenu() { mEditorSplitter->forEachEditor( [&]( UICodeEditor* editor ) { editor->setEnableColorPickerOnSelection( mConfig.editor.colorPreview ); } ); + } else if ( item->getText() == "Show Document Info" ) { + mConfig.editor.showDocInfo = item->asType()->isActive(); + if ( mDocInfo ) + mDocInfo->setVisible( mConfig.editor.showDocInfo ); + if ( mEditorSplitter->getCurEditor() ) + updateDocInfo( mEditorSplitter->getCurEditor()->getDocument() ); + } else if ( item->getText() == "UI Scale Factor (Pixel Density)" ) { + UIMessageBox* msgBox = UIMessageBox::New( + UIMessageBox::INPUT, "Set the UI scale factor (pixel density):\nMinimum value is " + "1, and maximum 6. Requires restart." ); + msgBox->setTitle( mWindowTitle ); + msgBox->getTextInput()->setText( + String::format( "%.2f", mConfig.window.pixelDensity ) ); + msgBox->setCloseShortcut( {KEY_ESCAPE, 0} ); + msgBox->show(); + msgBox->addEventListener( Event::MsgBoxConfirmClick, [&, msgBox]( const Event* ) { + msgBox->closeWindow(); + Float val; + if ( String::fromString( val, msgBox->getTextInput()->getText() ) && val >= 1 && + val <= 6 ) { + if ( mConfig.window.pixelDensity != val ) { + mConfig.window.pixelDensity = val; + UIMessageBox* msg = UIMessageBox::New( + UIMessageBox::OK, + "New UI scale factor assigned.\nPlease restart the application." ); + msg->show(); + setFocusEditorOnClose( msg ); + } else if ( mEditorSplitter && mEditorSplitter->getCurEditor() ) { + mEditorSplitter->getCurEditor()->setFocus(); + } + } else { + UIMessageBox* msg = UIMessageBox::New( UIMessageBox::OK, "Invalid value!" ); + msg->show(); + setFocusEditorOnClose( msg ); + } + } ); } else if ( item->getText() == "Editor Font Size" ) { UIMessageBox* msgBox = UIMessageBox::New( UIMessageBox::INPUT, "Set the editor font size:" ); @@ -644,13 +684,10 @@ UIMenu* App::createViewMenu() { editor->setFontSize( mConfig.editor.fontSize.asDp( 0, Sizef(), mDisplayDPI ) ); } ); } ); - msgBox->addEventListener( Event::OnClose, [&]( const Event* ) { - if ( mEditorSplitter->getCurEditor() ) - mEditorSplitter->getCurEditor()->setFocus(); - } ); + setFocusEditorOnClose( msgBox ); } else if ( item->getText() == "UI Font Size" ) { - UIMessageBox* msgBox = UIMessageBox::New( - UIMessageBox::INPUT, "Set the UI font size:" ); + UIMessageBox* msgBox = + UIMessageBox::New( UIMessageBox::INPUT, "Set the UI font size:" ); msgBox->setTitle( mWindowTitle ); msgBox->getTextInput()->setText( mConfig.ui.fontSize.toString() ); msgBox->setCloseShortcut( {KEY_ESCAPE, 0} ); @@ -673,10 +710,7 @@ UIMenu* App::createViewMenu() { } ); msgBox->closeWindow(); } ); - msgBox->addEventListener( Event::OnClose, [&]( const Event* ) { - if ( mEditorSplitter->getCurEditor() ) - mEditorSplitter->getCurEditor()->setFocus(); - } ); + setFocusEditorOnClose( msgBox ); } else if ( item->getText() == "Line Breaking Column" ) { UIMessageBox* msgBox = UIMessageBox::New( UIMessageBox::INPUT, "Set Line Breaking Column:\n" @@ -696,10 +730,7 @@ UIMenu* App::createViewMenu() { msgBox->closeWindow(); } } ); - msgBox->addEventListener( Event::OnClose, [&]( const Event* ) { - if ( mEditorSplitter->getCurEditor() ) - mEditorSplitter->getCurEditor()->setFocus(); - } ); + setFocusEditorOnClose( msgBox ); } else if ( "Zoom In" == item->getText() ) { mEditorSplitter->zoomIn(); } else if ( "Zoom Out" == item->getText() ) { @@ -718,6 +749,13 @@ UIMenu* App::createViewMenu() { return mViewMenu; } +void App::setFocusEditorOnClose( UIMessageBox* msgBox ) { + msgBox->addEventListener( Event::OnClose, [&]( const Event* ) { + if ( mEditorSplitter && mEditorSplitter->getCurEditor() ) + mEditorSplitter->getCurEditor()->setFocus(); + } ); +} + Drawable* App::findIcon( const std::string& name ) { return mUISceneNode->findIcon( name ); } @@ -819,6 +857,7 @@ UIMenu* App::createDocumentMenu() { mConfig.editor.windowsLineEndings = winLe; mEditorSplitter->getCurEditor()->getDocument().setLineEnding( winLe ? TextDocument::LineEnding::CRLF : TextDocument::LineEnding::LF ); + updateDocInfo( mEditorSplitter->getCurEditor()->getDocument() ); } } ); @@ -961,16 +1000,27 @@ void App::onDocumentSelectionChange( UICodeEditor* editor, TextDocument& doc ) { onDocumentModified( editor, doc ); } +void App::onDocumentCursorPosChange( UICodeEditor*, TextDocument& doc ) { + updateDocInfo( doc ); +} + +void App::updateDocInfo( TextDocument& doc ) { + if ( mConfig.editor.showDocInfo && mDocInfoText ) { + mDocInfoText->setText( String::format( + "line: %lld / %lu col: %lld %s", doc.getSelection().start().line() + 1, + doc.linesCount(), doc.getSelection().start().column() + 1, + doc.getLineEnding() == TextDocument::LineEnding::LF ? "LF" : "CRLF" ) ); + } +} + void App::onCodeEditorFocusChange( UICodeEditor* editor ) { + updateDocInfo( editor->getDocument() ); if ( mSearchState.editor && mSearchState.editor != editor ) { - String word; - /*if ( mEditorSplitter->editorExists( mSearchState.editor ) )*/ { - word = mSearchState.editor->getHighlightWord(); - mSearchState.editor->setHighlightWord( "" ); - mSearchState.editor->setHighlightTextRange( TextRange() ); - mSearchState.text = ""; - mSearchState.range = TextRange(); - } + String word = mSearchState.editor->getHighlightWord(); + mSearchState.editor->setHighlightWord( "" ); + mSearchState.editor->setHighlightTextRange( TextRange() ); + mSearchState.text = ""; + mSearchState.range = TextRange(); if ( editor ) { mSearchState.editor = editor; mSearchState.editor->setHighlightWord( word ); @@ -1339,6 +1389,8 @@ void App::init( const std::string& file, const Float& pidelDensity ) { padding-left: 4dp; padding-right: 4dp; padding-bottom: 3dp; + margin-bottom: 2dp; + margin-top: 2dp; } .close_button { width: 12dp; @@ -1363,14 +1415,29 @@ void App::init( const std::string& file, const Float& pidelDensity ) { #settings:hover { color: var(--primary); } + #doc_info { + background-color: var(--back); + margin-bottom: 22dp; + margin-right: 22dp; + border-radius: 8dp; + padding: 6dp; + opacity: 0.8; + } + #doc_info > TextView { + color: var(--font); + } - - - + + + + + + + - + @@ -1402,6 +1469,9 @@ void App::init( const std::string& file, const Float& pidelDensity ) { mUISceneNode->loadLayoutFromString( baseUI ); mUISceneNode->bind( "code_container", mBaseLayout ); mUISceneNode->bind( "search_bar", mSearchBarLayout ); + mUISceneNode->bind( "doc_info", mDocInfo ); + mUISceneNode->bind( "doc_info_text", mDocInfoText ); + mDocInfo->setVisible( mConfig.editor.showDocInfo ); mSearchBarLayout->setVisible( false )->setEnabled( false ); UIIconTheme* iconTheme = UIIconTheme::New( "remixicon" ); Float menuIconSize = mConfig.ui.fontSize.asPixels( 0, Sizef(), mDisplayDPI ); @@ -1441,6 +1511,7 @@ void App::init( const std::string& file, const Float& pidelDensity ) { addIcon( "ok", 0xeb7a, buttonIconSize ); addIcon( "cancel", 0xeb98, buttonIconSize ); addIcon( "color-picker", 0xf13d, buttonIconSize ); + addIcon( "pixel-density", 0xed8c, buttonIconSize ); mUISceneNode->getUIIconThemeManager()->setCurrentTheme( iconTheme ); diff --git a/src/tools/codeeditor/codeeditor.hpp b/src/tools/codeeditor/codeeditor.hpp index 7b8b4d868..00db3459e 100644 --- a/src/tools/codeeditor/codeeditor.hpp +++ b/src/tools/codeeditor/codeeditor.hpp @@ -64,6 +64,7 @@ struct CodeEditorConfig { bool colorPickerSelection{false}; bool colorPreview{false}; bool autoComplete{true}; + bool showDocInfo{true}; int indentWidth{4}; int tabWidth{4}; int lineBreakingColumn{100}; @@ -141,6 +142,8 @@ class App : public UICodeEditorSplitter::Client { UITextView* mSettingsButton{nullptr}; UIPopUpMenu* mColorSchemeMenu{nullptr}; UIPopUpMenu* mFiletypeMenu{nullptr}; + UILinearLayout* mDocInfo{nullptr}; + UITextView* mDocInfoText{nullptr}; IniFile mIni; IniFile mIniState; std::vector mRecentFiles; @@ -220,9 +223,15 @@ class App : public UICodeEditorSplitter::Client { void onDocumentSelectionChange( UICodeEditor* editor, TextDocument& ); + void onDocumentCursorPosChange( UICodeEditor* editor, TextDocument& ); + void onCodeEditorFocusChange( UICodeEditor* editor ); bool setAutoComplete( bool enable ); + + void updateDocInfo( TextDocument& doc ); + + void setFocusEditorOnClose( UIMessageBox* msgBox ); }; #endif // EE_TOOLS_CODEEDITOR_HPP