diff --git a/bin/assets/icon/ecode.ico b/bin/assets/icon/ecode.ico new file mode 100644 index 000000000..9700d471f Binary files /dev/null and b/bin/assets/icon/ecode.ico differ diff --git a/bin/assets/icon/ecode.png b/bin/assets/icon/ecode.png new file mode 100644 index 000000000..f02eeb34f Binary files /dev/null and b/bin/assets/icon/ecode.png differ diff --git a/bin/assets/icon/ecode.rc b/bin/assets/icon/ecode.rc new file mode 100644 index 000000000..cdcc4d44f --- /dev/null +++ b/bin/assets/icon/ecode.rc @@ -0,0 +1 @@ +1 ICON ecode.ico \ No newline at end of file diff --git a/bin/assets/ui/breeze.css b/bin/assets/ui/breeze.css index c0a347a10..fa1725452 100644 --- a/bin/assets/ui/breeze.css +++ b/bin/assets/ui/breeze.css @@ -114,6 +114,7 @@ TextEdit, TextInput, TextInputPassword, TextView, +Anchor, Tooltip, MenuBar::button, Window::title, @@ -125,6 +126,7 @@ listview::cell::text { } TextView, +Anchor, TextEdit, TextInput, TextInputPassword, @@ -133,6 +135,15 @@ SpinBox::input, { selection-back-color: var(--primary); } +Anchor { + cursor: arrow; +} + +Anchor:hover { + color: var(--primary); + cursor: hand; +} + PushButton, SelectButton, DropDownList { diff --git a/docs/articles/cssspecification.md b/docs/articles/cssspecification.md index a8631439e..6bd787e33 100644 --- a/docs/articles/cssspecification.md +++ b/docs/articles/cssspecification.md @@ -686,7 +686,7 @@ gravity: center_horizontal|bottom; ### gravity-owner -Widgets elements can inform that own childs position using a special flag on its implementation +Widgets elements can inform that own childs position using a special flag on its implementation (UI_OWNS_CHILDS_POSITION). Sometimes some layouts may need to override the parent behavior that uses that flag. This flag will let the layout manage his gravity against its parent in all cases. @@ -809,6 +809,16 @@ Sets the hint font stroke (the outline) width. --- +### href + +Specifies the link destination of an Anchor element + +* Applicable to: EE::UI::UIAnchor (Anchor) +* Data Type: [string](#string-data-type) +* Default value: `0dp` + +--- + ### hscroll-mode Sets the horizontal scroll mode to any scrollable element. @@ -1800,7 +1810,7 @@ Sets the text stroke (also known as text outline) width/thickness. ### text-transform -The text-transform CSS property specifies how to capitalize an element's text. It can be used to +The text-transform CSS property specifies how to capitalize an element's text. It can be used to make text appear in all-uppercase or all-lowercase, or with each word capitalized. * Applicable to: EE::UI::UITextView (TextView) and any element that holds inside or extends from a @@ -2446,10 +2456,10 @@ Read [position](https://developer.mozilla.org/en-US/docs/Web/CSS/position_value) For EE::UI::UIImage (Image), background-image, foreground-image (all the examples are valid). -For a EE::UI::UITextureRegion (TextureRegion) only the examples with: @textureregion, @drawable, +For a EE::UI::UITextureRegion (TextureRegion) only the examples with: @textureregion, @drawable, drawable_resource_name from a texture region resource are valid. -For a EE::UI::UISprite (Sprite) only the examples with: all the examples are valid except for @9p +For a EE::UI::UISprite (Sprite) only the examples with: all the examples are valid except for @9p and http/s resources. Valid resources path: diff --git a/include/eepp/ui/css/propertydefinition.hpp b/include/eepp/ui/css/propertydefinition.hpp index 8e3a32216..72505b35f 100644 --- a/include/eepp/ui/css/propertydefinition.hpp +++ b/include/eepp/ui/css/propertydefinition.hpp @@ -209,6 +209,7 @@ enum class PropertyId : Uint32 { SelectOnClick = String::hash( "select-on-click" ), LineSpacing = String::hash( "line-spacing" ), GravityOwner = String::hash( "gravity-owner" ), + Href = String::hash( "href" ), }; enum class PropertyType : Uint32 { diff --git a/include/eepp/ui/uicodeeditor.hpp b/include/eepp/ui/uicodeeditor.hpp index d2c75cf93..f9e9f45e7 100644 --- a/include/eepp/ui/uicodeeditor.hpp +++ b/include/eepp/ui/uicodeeditor.hpp @@ -631,7 +631,7 @@ class EE_API UICodeEditor : public UIWidget, public TextDocument::Client { bool mAutoCloseXMLTags{ false }; bool mFindReplaceEnabled{ true }; bool mShowIndentationGuides{ false }; - bool mShowLinesRelativePosition; + bool mShowLinesRelativePosition{ false }; std::atomic mHighlightWordProcessing{ false }; TextRange mLinkPosition; String mLink; diff --git a/include/eepp/ui/uitextview.hpp b/include/eepp/ui/uitextview.hpp index a6fbb0de6..ebaab8f04 100644 --- a/include/eepp/ui/uitextview.hpp +++ b/include/eepp/ui/uitextview.hpp @@ -173,6 +173,29 @@ class EE_API UITextView : public UIWidget { void resetSelCache(); }; +class EE_API UIAnchor : public UITextView { + public: + static UIAnchor* New(); + + UIAnchor(); + + virtual bool applyProperty( const StyleSheetProperty& attribute ); + + virtual std::string getPropertyString( const PropertyDefinition* propertyDef, + const Uint32& propertyIndex = 0 ) const; + + virtual std::vector getPropertiesImplemented() const; + + void setHref( const std::string& href ); + + const std::string& getHref() const; + + protected: + std::string mHref; + + virtual Uint32 onKeyDown( const KeyEvent& event ); +}; + }} // namespace EE::UI #endif diff --git a/projects/haiku/ecode/build.app.sh b/projects/haiku/ecode/build.app.sh index 266b78bfa..50dff311a 100755 --- a/projects/haiku/ecode/build.app.sh +++ b/projects/haiku/ecode/build.app.sh @@ -10,7 +10,7 @@ cd "$DIRPATH" || exit rm -rf ./ecode.app mkdir -p ecode.app/assets mkdir -p ecode.app/lib -cp ../../../bin/assets/icon/ee.png ecode.app/ecode.png +cp ../../../bin/assets/icon/ecode.png ecode.app/ecode.png cp ../../../libs/haiku/libeepp.so ecode.app/lib/ cp ../../../bin/ecode ecode.app/ cp -L /boot/system/lib/libSDL2-2.0.so.0 ecode.app/lib/ @@ -29,7 +29,7 @@ cp -r ../../../bin/assets/fonts/NotoColorEmoji.ttf ecode.app/assets/fonts/ cp -r ../../../bin/assets/fonts/DroidSansFallbackFull.ttf ecode.app/assets/fonts/ cp -r ../../../bin/assets/plugins ecode.app/assets/ mkdir -p ecode.app/assets/icon/ -cp -r ../../../bin/assets/icon/ee.png ecode.app/assets/icon/ +cp -r ../../../bin/assets/icon/ecode.png ecode.app/assets/icon/ mkdir ecode.app/assets/ui cp ../../../bin/assets/ui/breeze.css ecode.app/assets/ui/ diff --git a/projects/linux/ecode/build.app.sh b/projects/linux/ecode/build.app.sh index 62729abd8..82a048e7e 100755 --- a/projects/linux/ecode/build.app.sh +++ b/projects/linux/ecode/build.app.sh @@ -28,7 +28,7 @@ mkdir -p ecode.app/libs chmod +x AppRun cp AppRun ecode.app/ cp ecode.desktop ecode.app/ -cp ../../../bin/assets/icon/ee.png ecode.app/ecode.png +cp ../../../bin/assets/icon/ecode.png ecode.app/ecode.png cp ../../../libs/linux/libeepp.so ecode.app/libs/ cp ../../../bin/ecode ecode.app/ecode.bin cp -L "$(whereis libSDL2-2.0.so.0 | awk '{print $NF}')" ecode.app/libs/ @@ -47,7 +47,7 @@ cp -r ../../../bin/assets/fonts/NotoColorEmoji.ttf ecode.app/assets/fonts/ cp -r ../../../bin/assets/fonts/DroidSansFallbackFull.ttf ecode.app/assets/fonts/ cp -r ../../../bin/assets/plugins ecode.app/assets/ mkdir -p ecode.app/assets/icon/ -cp -r ../../../bin/assets/icon/ee.png ecode.app/assets/icon/ +cp -r ../../../bin/assets/icon/ecode.png ecode.app/assets/icon/ mkdir ecode.app/assets/ui cp ../../../bin/assets/ui/breeze.css ecode.app/assets/ui/ cp ../../../bin/assets/ca-bundle.pem ecode.app/assets/ca-bundle.pem diff --git a/projects/mingw32/ecode/build.app.sh b/projects/mingw32/ecode/build.app.sh index a77c278cd..47ea51a91 100755 --- a/projects/mingw32/ecode/build.app.sh +++ b/projects/mingw32/ecode/build.app.sh @@ -54,7 +54,7 @@ cp -r ../../../bin/assets/plugins ecode/assets/ mkdir ecode/assets/ui cp ../../../bin/assets/ui/breeze.css ecode/assets/ui/ mkdir -p ecode/assets/icon -cp ../../../bin/assets/icon/ee.png ecode/assets/icon/ +cp ../../../bin/assets/icon/ecode.png ecode/assets/icon/ cp ../../../bin/assets/ca-bundle.pem ecode/assets/ca-bundle.pem VERSIONPATH=../../../src/tools/ecode/version.hpp diff --git a/src/eepp/ui/css/stylesheetspecification.cpp b/src/eepp/ui/css/stylesheetspecification.cpp index 51529f0f9..c36634804 100644 --- a/src/eepp/ui/css/stylesheetspecification.cpp +++ b/src/eepp/ui/css/stylesheetspecification.cpp @@ -390,6 +390,7 @@ void StyleSheetSpecification::registerDefaultProperties() { registerProperty( "text-as-fallback", "false" ).setType( PropertyType::Bool ); registerProperty( "select-on-click", "false" ).setType( PropertyType::Bool ); registerProperty( "gravity-owner", "false" ).setType( PropertyType::Bool ); + registerProperty( "href", "" ).setType( PropertyType::String ); // Shorthands registerShorthand( "margin", { "margin-top", "margin-right", "margin-bottom", "margin-left" }, diff --git a/src/eepp/ui/uirelativelayout.cpp b/src/eepp/ui/uirelativelayout.cpp index b93616b00..aec875098 100644 --- a/src/eepp/ui/uirelativelayout.cpp +++ b/src/eepp/ui/uirelativelayout.cpp @@ -43,8 +43,17 @@ void UIRelativeLayout::updateLayout() { if ( getParent()->isWidget() ) padding = static_cast( getParent() )->getPadding(); - setInternalWidth( getParent()->getSize().getWidth() - mLayoutMargin.Left - - mLayoutMargin.Right - padding.Left - padding.Right ); + Float width = getParent()->getSize().getWidth() - mLayoutMargin.Left - mLayoutMargin.Right - + padding.Left - padding.Right; + + if ( !mMaxWidthEq.empty() || !mMaxHeightEq.empty() ) { + Float maxWidth( getMaxSize().getWidth() - mLayoutMargin.Left - mLayoutMargin.Right - + padding.Left - padding.Right ); + if ( maxWidth > 0 && maxWidth < width ) + width = maxWidth; + } + + setInternalWidth( width ); } if ( getLayoutHeightPolicy() == SizePolicy::MatchParent ) { @@ -53,8 +62,17 @@ void UIRelativeLayout::updateLayout() { if ( getParent()->isWidget() ) padding = static_cast( getParent() )->getPadding(); - setInternalHeight( getParent()->getSize().getHeight() - mLayoutMargin.Top - - mLayoutMargin.Bottom - padding.Top - padding.Bottom ); + Float height = getParent()->getSize().getHeight() - mLayoutMargin.Top - + mLayoutMargin.Bottom - padding.Top - padding.Bottom; + + if ( !mMaxHeightEq.empty() || !mMaxHeightEq.empty() ) { + Float maxHeight( getMaxSize().getHeight() - mLayoutMargin.Left - mLayoutMargin.Right - + padding.Left - padding.Right ); + if ( maxHeight > 0 && maxHeight < height ) + height = maxHeight; + } + + setInternalHeight( height ); } Node* child = mChild; diff --git a/src/eepp/ui/uiscenenode.cpp b/src/eepp/ui/uiscenenode.cpp index 03da7cd66..6d8208827 100644 --- a/src/eepp/ui/uiscenenode.cpp +++ b/src/eepp/ui/uiscenenode.cpp @@ -852,8 +852,12 @@ void UISceneNode::processStyleSheetAtRules( const StyleSheet& styleSheet ) { void UISceneNode::loadFontFaces( const StyleSheetStyleVector& styles ) { for ( auto& style : styles ) { - CSS::StyleSheetProperty familyProp( *style->getPropertyById( PropertyId::FontFamily ) ); - CSS::StyleSheetProperty srcProp( *style->getPropertyById( PropertyId::Src ) ); + auto family = style->getPropertyById( PropertyId::FontFamily ); + auto src = style->getPropertyById( PropertyId::Src ); + if ( src == nullptr || family == nullptr ) + return; + CSS::StyleSheetProperty familyProp( *family ); + CSS::StyleSheetProperty srcProp( *src ); if ( !familyProp.isEmpty() && !srcProp.isEmpty() ) { Font* fontSearch = FontManager::instance()->getByName( familyProp.getValue() ); diff --git a/src/eepp/ui/uitextview.cpp b/src/eepp/ui/uitextview.cpp index 4058dc9aa..1e8a6c183 100644 --- a/src/eepp/ui/uitextview.cpp +++ b/src/eepp/ui/uitextview.cpp @@ -11,6 +11,7 @@ #include #include #include +#include namespace EE { namespace UI { @@ -173,8 +174,7 @@ UITextView* UITextView::setOutlineColor( const Color& outlineColor ) { } UITextView* UITextView::setFontStyle( const Uint32& fontStyle ) { - if ( mFontStyleConfig.Style != fontStyle ) { - mTextCache->setStyle( fontStyle ); + if ( mFontStyleConfig.Style != fontStyle ) { mTextCache->setStyle( fontStyle ); mFontStyleConfig.Style = fontStyle; recalculate(); onFontStyleChanged(); @@ -265,7 +265,9 @@ UITextView* UITextView::setFontShadowColor( const Color& color ) { mFontStyleConfig.Style &= ~Text::Shadow; Color newColor( color.r, color.g, color.b, color.a * mAlpha / 255.f ); mTextCache->setShadowColor( newColor ); + mTextCache->setStyle( mFontStyleConfig.Style ); onFontStyleChanged(); + recalculate(); invalidateDraw(); } @@ -819,4 +821,74 @@ void UITextView::setTextAlign( const Uint32& align ) { onAlignChange(); } +UIAnchor* UIAnchor::New() { + return eeNew( UIAnchor, () ); +} + +UIAnchor::UIAnchor() : UITextView( "anchor" ) { + addMouseClickListener( + [this]( const MouseEvent* ) { + if ( !mHref.empty() ) + Engine::instance()->openURI( mHref ); + }, + EE_BUTTON_LEFT ); +} + +bool UIAnchor::applyProperty( const StyleSheetProperty& attribute ) { + if ( !checkPropertyDefinition( attribute ) ) + return false; + + switch ( attribute.getPropertyDefinition()->getPropertyId() ) { + case PropertyId::Href: + setHref( attribute.asString() ); + break; + default: + UITextView::applyProperty( attribute ); + break; + } + + return true; +} + +void UIAnchor::setHref( const std::string& href ) { + if ( href != mHref ) { + mHref = href; + } +} + +const std::string& UIAnchor::getHref() const { + return mHref; +} + +Uint32 UIAnchor::onKeyDown( const KeyEvent& event ) { + if ( event.getKeyCode() == KEY_KP_ENTER || event.getKeyCode() == KEY_RETURN ) { + if ( !mHref.empty() ) { + Engine::instance()->openURI( mHref ); + return 1; + } + } + + return 0; +} + +std::string UIAnchor::getPropertyString( const PropertyDefinition* propertyDef, + const Uint32& propertyIndex ) const { + if ( NULL == propertyDef ) + return ""; + + switch ( propertyDef->getPropertyId() ) { + case PropertyId::Href: + return mHref; + default: + return UITextView::getPropertyString( propertyDef, propertyIndex ); + } +} + +std::vector UIAnchor::getPropertiesImplemented() const { + auto props = UITextView::getPropertiesImplemented(); + auto local = { PropertyId::Href }; + props.insert( props.end(), local.begin(), local.end() ); + return props; +} + }} // namespace EE::UI diff --git a/src/eepp/ui/uiwidgetcreator.cpp b/src/eepp/ui/uiwidgetcreator.cpp index 0cc14f0e9..7fd12fe2a 100644 --- a/src/eepp/ui/uiwidgetcreator.cpp +++ b/src/eepp/ui/uiwidgetcreator.cpp @@ -95,6 +95,7 @@ void UIWidgetCreator::createBaseWidgetList() { registeredWidget["menucheckbox"] = UIMenuCheckBox::New; registeredWidget["menuradiobutton"] = UIMenuRadioButton::New; registeredWidget["menuseparator"] = UIMenuSeparator::New; + registeredWidget["anchor"] = UIAnchor::New; registeredWidget["hbox"] = UILinearLayout::NewHorizontal; registeredWidget["vbox"] = UILinearLayout::NewVertical; @@ -109,7 +110,8 @@ void UIWidgetCreator::createBaseWidgetList() { registeredWidget["button"] = UIPushButton::New; registeredWidget["rlay"] = UIRelativeLayout::New; registeredWidget["tooltip"] = UITooltip::New; - + registeredWidget["tv"] = UITextView::New; + registeredWidget["a"] = UIAnchor::New; sBaseListCreated = true; } diff --git a/src/tools/ecode/appconfig.cpp b/src/tools/ecode/appconfig.cpp index 516544e2c..23857ecc6 100644 --- a/src/tools/ecode/appconfig.cpp +++ b/src/tools/ecode/appconfig.cpp @@ -70,7 +70,7 @@ void AppConfig::load( const std::string& confPath, std::string& keybindingsPath, windowState.size.setHeight( iniState.getValueI( "window", "height", defWinSize.getHeight() ) ); windowState.maximized = iniState.getValueB( "window", "maximized", false ); windowState.pixelDensity = iniState.getValueF( "window", "pixeldensity" ); - windowState.winIcon = ini.getValue( "window", "winicon", resPath + "icon/ee.png" ); + windowState.winIcon = ini.getValue( "window", "winicon", resPath + "icon/ecode.png" ); windowState.panelPartition = iniState.getValue( "window", "panel_partition", "15%" ); windowState.displayIndex = iniState.getValueI( "window", "display_index", 0 ); windowState.position.x = iniState.getValueI( "window", "x", -1 ); diff --git a/src/tools/ecode/plugins/lsp/lspclientserver.cpp b/src/tools/ecode/plugins/lsp/lspclientserver.cpp index 92adcee63..0adcd744f 100644 --- a/src/tools/ecode/plugins/lsp/lspclientserver.cpp +++ b/src/tools/ecode/plugins/lsp/lspclientserver.cpp @@ -1079,6 +1079,15 @@ bool LSPClientServer::socketConnect() { return false; } +void LSPClientServer::socketInitialize() { + getThreadPool()->run( [this]() { + bool ret = socketConnect(); + mUsingSocket = true; + if ( ret ) + initialize(); + } ); +} + bool LSPClientServer::start() { std::string cmd( mLSP.command ); if ( !mLSP.commandParameters.empty() ) { @@ -1101,20 +1110,16 @@ bool LSPClientServer::start() { } if ( ret && !mLSP.host.empty() ) { - ret = socketConnect(); - mUsingSocket = true; - if ( ret ) - initialize(); + socketInitialize(); + ret = true; } return ret; } else { - bool ret = socketConnect(); - mUsingSocket = true; - - if ( ret ) - initialize(); - return ret; + if ( !mLSP.host.empty() && mLSP.port != 0 ) { + socketInitialize(); + return true; + } } return false; } diff --git a/src/tools/ecode/plugins/lsp/lspclientserver.hpp b/src/tools/ecode/plugins/lsp/lspclientserver.hpp index df597a94c..9acee3055 100644 --- a/src/tools/ecode/plugins/lsp/lspclientserver.hpp +++ b/src/tools/ecode/plugins/lsp/lspclientserver.hpp @@ -273,6 +273,8 @@ class LSPClientServer { bool needsAsync(); bool socketConnect(); + + void socketInitialize(); }; } // namespace ecode diff --git a/src/tools/ecode/settingsmenu.cpp b/src/tools/ecode/settingsmenu.cpp index db5cf7437..2855d98ad 100644 --- a/src/tools/ecode/settingsmenu.cpp +++ b/src/tools/ecode/settingsmenu.cpp @@ -1601,7 +1601,7 @@ void SettingsMenu::createProjectTreeMenu( const FileInfo& file ) { } } - mProjectTreeMenu->add( i18n( "open_folder", "Open File" ), findIcon( "document-open" ) ) + mProjectTreeMenu->add( i18n( "open_file", "Open File" ), findIcon( "document-open" ) ) ->setId( "open_file" ); mProjectTreeMenu ->add( i18n( "open_containin_folder", "Open Containing Folder..." ), diff --git a/src/tools/uieditor/uieditor.cpp b/src/tools/uieditor/uieditor.cpp index 1bca4d5f8..9123ec579 100644 --- a/src/tools/uieditor/uieditor.cpp +++ b/src/tools/uieditor/uieditor.cpp @@ -1197,7 +1197,7 @@ void App::init( const Float& pixelDensityConf, const bool& useAppTheme, const st mWindow = Engine::instance()->createWindow( WindowSettings( 1280, 720, "eepp - UI Editor", WindowStyle::Default, WindowBackend::Default, 32, mResPath + "assets/icon/ee.png", pixelDensity ), - ContextSettings( true, GLv_default, true, 24, 1, 0, true ) ); + ContextSettings( false, GLv_default, true, 24, 1, 0, true ) ); if ( mWindow->isOpen() ) { PixelDensity::setPixelDensity( eemax( mWindow->getScale(), pixelDensity ) );