diff --git a/bin/assets/i18n/de.xml b/bin/assets/i18n/de.xml
index 23afaa892..6dd25df34 100644
--- a/bin/assets/i18n/de.xml
+++ b/bin/assets/i18n/de.xml
@@ -1271,8 +1271,11 @@ Für sichtbare Änderung ecode neu starten.
Nachricht kopieren
Branch hinzufügen...
Tag hinzufügen
+ Tag hinzufügen & pushen
Tag hinzufügen...
Tag zu Commit %s hinzufügen
+ Tag-Name
+ Nachricht für annotiertes Tag (optional)
Branch bei Commit %s erstellen.
Zusammenführen...
Cherry-Pick...
diff --git a/bin/assets/i18n/en.xml b/bin/assets/i18n/en.xml
index 7a809bcd2..97081f4e4 100644
--- a/bin/assets/i18n/en.xml
+++ b/bin/assets/i18n/en.xml
@@ -1256,8 +1256,11 @@ Restart ecode to see the changes.
Copy Message
Add Branch...
Add Tag
+ Add Tag & Push
Add Tag...
Add tag to commit %s
+ Tag name
+ Annotated tag message (optional)
Create a branch at commit %s.
Merge...
Cherry-Pick...
diff --git a/bin/assets/i18n/fr.xml b/bin/assets/i18n/fr.xml
index c53b4e7b3..8c53a8b53 100644
--- a/bin/assets/i18n/fr.xml
+++ b/bin/assets/i18n/fr.xml
@@ -1255,8 +1255,11 @@ Redémarrer ecode pour voir les changements.
Copier le message
Ajouter une branche...
Ajouter une étiquette
+ Ajouter et pousser l’étiquette
Ajouter une étiquette...
Ajouter une étiquette au commit %s
+ Nom de l’étiquette
+ Message de l’étiquette annotée (facultatif)
Créer une branche au commit %s.
Fusionner...
Cherry-pick...
diff --git a/bin/assets/i18n/zh.xml b/bin/assets/i18n/zh.xml
index 38f0be4c5..2614e7a91 100644
--- a/bin/assets/i18n/zh.xml
+++ b/bin/assets/i18n/zh.xml
@@ -1060,8 +1060,11 @@ file in the directory tree.
复制提交消息
添加分支...
添加标签
+ 添加并推送标签
添加标签...
为提交 %s 添加标签
+ 标签名称
+ 附注标签消息(可选)
在提交 %s 创建分支。
合并...
拣选提交...
diff --git a/bin/assets/ui/breeze.css b/bin/assets/ui/breeze.css
index f8fe0654e..d88c4d628 100644
--- a/bin/assets/ui/breeze.css
+++ b/bin/assets/ui/breeze.css
@@ -467,6 +467,7 @@ TextArea {
padding-right: var(--base-horizontal-padding);
padding-top: var(--base-vertical-padding);
padding-bottom: var(--base-vertical-padding);
+ hint-color: var(--font-hint);
transition: all 0.15;
}
diff --git a/include/eepp/ui/uitextedit.hpp b/include/eepp/ui/uitextedit.hpp
index 1ad77ab5a..085352eeb 100644
--- a/include/eepp/ui/uitextedit.hpp
+++ b/include/eepp/ui/uitextedit.hpp
@@ -26,13 +26,68 @@ class EE_API UITextEdit : public UICodeEditor {
void setWordWrap( bool enabled );
+ const String& getHint() const;
+
+ UITextEdit* setHint( const String& hint );
+
+ const Color& getHintColor() const;
+
+ UITextEdit* setHintColor( const Color& hintColor );
+
+ const Color& getHintShadowColor() const;
+
+ UITextEdit* setHintShadowColor( const Color& shadowColor );
+
+ const Vector2f& getHintShadowOffset() const;
+
+ UITextEdit* setHintShadowOffset( const Vector2f& shadowOffset );
+
+ Font* getHintFont() const;
+
+ UITextEdit* setHintFont( Font* font );
+
+ Uint32 getHintFontSize() const;
+
+ UITextEdit* setHintFontSize( const Uint32& characterSize );
+
+ const Uint32& getHintFontStyle() const;
+
+ UITextEdit* setHintFontStyle( const Uint32& fontStyle );
+
+ const Float& getHintOutlineThickness() const;
+
+ UITextEdit* setHintOutlineThickness( const Float& outlineThickness );
+
+ const Color& getHintOutlineColor() const;
+
+ UITextEdit* setHintOutlineColor( const Color& outlineColor );
+
+ void setHintDisplay( HintDisplay display );
+
+ HintDisplay getHintDisplay() const;
+
virtual bool applyProperty( const StyleSheetProperty& attribute );
+ virtual std::string getPropertyString( const PropertyDefinition* propertyDef,
+ const Uint32& propertyIndex = 0 ) const;
+
+ virtual std::vector getPropertiesImplemented() const;
+
protected:
UITextEdit( const std::string& tag );
+ Text mHintCache;
+ FontStyleConfig mHintStyleConfig;
+ HintDisplay mHintDisplay{ HintDisplay::Always };
+
+ virtual void drawLineText( const Int64& line, Vector2f position, const Float& fontSize,
+ const Float& lineHeight,
+ const DocumentViewLineRange& visibleLineRange );
+
virtual void drawCursor( const Vector2f& startScroll, const Float& lineHeight,
const TextPosition& cursor );
+
+ virtual void onTextHintsChanged();
};
}} // namespace EE::UI
diff --git a/src/eepp/ui/uitextedit.cpp b/src/eepp/ui/uitextedit.cpp
index bfc4af68e..dd1b97c41 100644
--- a/src/eepp/ui/uitextedit.cpp
+++ b/src/eepp/ui/uitextedit.cpp
@@ -1,5 +1,6 @@
#include
#include
+#include
#include
#include
#include
@@ -45,6 +46,11 @@ UITextEdit::UITextEdit( const std::string& tag ) : UICodeEditor( tag, true, true
}
}
+ mHintCache.setTextHints( getWidgetTextDrawHints() );
+ setHintFont( theme && theme->getDefaultFont() ? theme->getDefaultFont() : getFont() );
+ setHintFontSize( theme ? theme->getDefaultFontSize()
+ : getUISceneNode()->getUIThemeManager()->getDefaultFontSize() );
+
disableEditorFeatures();
applyDefaultTheme();
}
@@ -90,6 +96,135 @@ void UITextEdit::setWordWrap( bool enabled ) {
setLineWrapMode( enabled ? LineWrapMode::Word : LineWrapMode::NoWrap );
}
+const String& UITextEdit::getHint() const {
+ return mHintCache.getString();
+}
+
+UITextEdit* UITextEdit::setHint( const String& hint ) {
+ if ( hint != mHintCache.getString() ) {
+ mHintCache.setString( hint );
+ invalidateDraw();
+ }
+ return this;
+}
+
+const Color& UITextEdit::getHintColor() const {
+ return mHintStyleConfig.getFontColor();
+}
+
+UITextEdit* UITextEdit::setHintColor( const Color& hintColor ) {
+ if ( hintColor != mHintStyleConfig.getFontColor() ) {
+ mHintCache.setFillColor( hintColor );
+ mHintStyleConfig.FontColor = hintColor;
+ invalidateDraw();
+ }
+ return this;
+}
+
+const Color& UITextEdit::getHintShadowColor() const {
+ return mHintStyleConfig.getFontShadowColor();
+}
+
+UITextEdit* UITextEdit::setHintShadowColor( const Color& shadowColor ) {
+ if ( shadowColor != mHintStyleConfig.getFontShadowColor() ) {
+ mHintCache.setShadowColor( shadowColor );
+ mHintStyleConfig.ShadowColor = shadowColor;
+ invalidateDraw();
+ }
+ return this;
+}
+
+const Vector2f& UITextEdit::getHintShadowOffset() const {
+ return mHintStyleConfig.getFontShadowOffset();
+}
+
+UITextEdit* UITextEdit::setHintShadowOffset( const Vector2f& shadowOffset ) {
+ if ( shadowOffset != mHintStyleConfig.getFontShadowOffset() ) {
+ mHintCache.setShadowOffset( shadowOffset );
+ mHintStyleConfig.ShadowOffset = shadowOffset;
+ invalidateDraw();
+ }
+ return this;
+}
+
+Font* UITextEdit::getHintFont() const {
+ return mHintStyleConfig.getFont();
+}
+
+UITextEdit* UITextEdit::setHintFont( Font* font ) {
+ if ( font != mHintStyleConfig.getFont() ) {
+ mHintCache.setFont( font );
+ mHintStyleConfig.Font = font;
+ invalidateDraw();
+ }
+ return this;
+}
+
+Uint32 UITextEdit::getHintFontSize() const {
+ return mHintCache.getCharacterSize();
+}
+
+UITextEdit* UITextEdit::setHintFontSize( const Uint32& characterSize ) {
+ if ( characterSize != mHintCache.getCharacterSize() ) {
+ mHintCache.setFontSize( characterSize );
+ mHintStyleConfig.CharacterSize = characterSize;
+ invalidateDraw();
+ }
+ return this;
+}
+
+const Uint32& UITextEdit::getHintFontStyle() const {
+ return mHintStyleConfig.Style;
+}
+
+UITextEdit* UITextEdit::setHintFontStyle( const Uint32& fontStyle ) {
+ if ( fontStyle != mHintStyleConfig.Style ) {
+ mHintCache.setStyle( fontStyle );
+ mHintStyleConfig.Style = fontStyle;
+ invalidateDraw();
+ }
+ return this;
+}
+
+const Float& UITextEdit::getHintOutlineThickness() const {
+ return mHintStyleConfig.OutlineThickness;
+}
+
+UITextEdit* UITextEdit::setHintOutlineThickness( const Float& outlineThickness ) {
+ if ( outlineThickness != mHintStyleConfig.OutlineThickness ) {
+ mHintCache.setOutlineThickness( outlineThickness );
+ mHintStyleConfig.OutlineThickness = outlineThickness;
+ invalidateDraw();
+ }
+ return this;
+}
+
+const Color& UITextEdit::getHintOutlineColor() const {
+ return mHintStyleConfig.OutlineColor;
+}
+
+UITextEdit* UITextEdit::setHintOutlineColor( const Color& outlineColor ) {
+ if ( outlineColor != mHintStyleConfig.OutlineColor ) {
+ mHintStyleConfig.OutlineColor = outlineColor;
+ Color color( outlineColor.r, outlineColor.g, outlineColor.b,
+ outlineColor.a * mAlpha / 255.f );
+ mHintCache.setOutlineColor( color );
+ invalidateDraw();
+ }
+ return this;
+}
+
+void UITextEdit::setHintDisplay( HintDisplay display ) {
+ if ( display != mHintDisplay ) {
+ mHintDisplay = display;
+ invalidateDraw();
+ }
+}
+
+HintDisplay UITextEdit::getHintDisplay() const {
+ return mHintDisplay;
+}
+
bool UITextEdit::applyProperty( const StyleSheetProperty& attribute ) {
if ( !checkPropertyDefinition( attribute ) )
return false;
@@ -101,6 +236,42 @@ bool UITextEdit::applyProperty( const StyleSheetProperty& attribute ) {
break;
case PropertyId::Wordwrap:
setWordWrap( attribute.asBool() );
+ break;
+ case PropertyId::Hint:
+ setHint( getTranslatorString( attribute.value() ) );
+ break;
+ case PropertyId::HintColor:
+ setHintColor( attribute.asColor() );
+ break;
+ case PropertyId::HintShadowColor:
+ setHintShadowColor( attribute.asColor() );
+ break;
+ case PropertyId::HintShadowOffset:
+ setHintShadowOffset( attribute.asVector2f() );
+ break;
+ case PropertyId::HintFontSize:
+ setHintFontSize( lengthFromValue( attribute ) );
+ break;
+ case PropertyId::HintFontFamily:
+ setHintFont(
+ getUISceneNode()
+ ? getUISceneNode()->getResourceScope()->findFont( attribute.value() ).get()
+ : nullptr );
+ break;
+ case PropertyId::HintFontStyle:
+ setHintFontStyle( attribute.asFontStyle() );
+ break;
+ case PropertyId::HintStrokeWidth:
+ setHintOutlineThickness( PixelDensity::dpToPx( attribute.asDpDimension() ) );
+ break;
+ case PropertyId::HintStrokeColor:
+ setHintOutlineColor( attribute.asColor() );
+ break;
+ case PropertyId::HintDisplay:
+ setHintDisplay( String::toLower( attribute.asString() ) == "focus"
+ ? HintDisplay::Focus
+ : HintDisplay::Always );
+ break;
default:
return UICodeEditor::applyProperty( attribute );
}
@@ -108,6 +279,65 @@ bool UITextEdit::applyProperty( const StyleSheetProperty& attribute ) {
return true;
}
+std::string UITextEdit::getPropertyString( const PropertyDefinition* propertyDef,
+ const Uint32& propertyIndex ) const {
+ if ( NULL == propertyDef )
+ return "";
+
+ switch ( propertyDef->getPropertyId() ) {
+ case PropertyId::Hint:
+ return getHint().toUtf8();
+ case PropertyId::HintColor:
+ return getHintColor().toHexString();
+ case PropertyId::HintShadowColor:
+ return getHintShadowColor().toHexString();
+ case PropertyId::HintShadowOffset:
+ return String::fromFloat( getHintShadowOffset().x ) + " " +
+ String::fromFloat( getHintShadowOffset().y );
+ case PropertyId::HintFontSize:
+ return String::format( "%ddp", getHintFontSize() );
+ case PropertyId::HintFontFamily:
+ return getHintFont() ? getUISceneNode()->getFontFamilyName( getHintFont() ) : "";
+ case PropertyId::HintFontStyle:
+ return Text::styleFlagToString( getHintFontStyle() );
+ case PropertyId::HintStrokeWidth:
+ return String::fromFloat( PixelDensity::dpToPx( getHintOutlineThickness() ), "px" );
+ case PropertyId::HintStrokeColor:
+ return getHintOutlineColor().toHexString();
+ case PropertyId::HintDisplay:
+ return mHintDisplay == HintDisplay::Always ? "always" : "focus";
+ default:
+ return UICodeEditor::getPropertyString( propertyDef, propertyIndex );
+ }
+}
+
+std::vector UITextEdit::getPropertiesImplemented() const {
+ auto props = UICodeEditor::getPropertiesImplemented();
+ auto local = { PropertyId::Hint,
+ PropertyId::HintColor,
+ PropertyId::HintShadowColor,
+ PropertyId::HintShadowOffset,
+ PropertyId::HintFontSize,
+ PropertyId::HintFontFamily,
+ PropertyId::HintFontStyle,
+ PropertyId::HintStrokeWidth,
+ PropertyId::HintStrokeColor,
+ PropertyId::HintDisplay };
+ props.insert( props.end(), local.begin(), local.end() );
+ return props;
+}
+
+void UITextEdit::drawLineText( const Int64& line, Vector2f position, const Float& fontSize,
+ const Float& lineHeight,
+ const DocumentViewLineRange& visibleLineRange ) {
+ UICodeEditor::drawLineText( line, position, fontSize, lineHeight, visibleLineRange );
+ if ( line == 0 && mDoc->isEmpty() && !mHintCache.getString().empty() &&
+ ( mHintDisplay == HintDisplay::Always || hasFocus() ) ) {
+ mHintCache.draw( std::trunc( position.x ), std::trunc( position.y ), Vector2f::One, 0.f,
+ getBlendMode() );
+ }
+}
+
void UITextEdit::drawCursor( const Vector2f& startScroll, const Float& lineHeight,
const TextPosition& cursor ) {
if ( mCursorVisible && !mLocked && isTextSelectionEnabled() ) {
@@ -121,4 +351,9 @@ void UITextEdit::drawCursor( const Vector2f& startScroll, const Float& lineHeigh
}
}
+void UITextEdit::onTextHintsChanged() {
+ UICodeEditor::onTextHintsChanged();
+ mHintCache.setTextHints( getWidgetTextDrawHints() );
+}
+
}} // namespace EE::UI
diff --git a/src/tools/ecode/plugins/git/git.cpp b/src/tools/ecode/plugins/git/git.cpp
index 2349878a5..f4917a4cb 100644
--- a/src/tools/ecode/plugins/git/git.cpp
+++ b/src/tools/ecode/plugins/git/git.cpp
@@ -950,6 +950,14 @@ Git::Result Git::createTag( const std::string& name, const std::string& revision
return result;
}
+Git::Result Git::pushTag( const std::string& name, const std::string& remote,
+ const std::string& projectDir ) {
+ Result result;
+ result.returnCode = git( { "push", remote, "refs/tags/" + name + ":refs/tags/" + name },
+ projectDir, result.result );
+ return result;
+}
+
Git::Result Git::deleteTag( const std::string& name, const std::string& projectDir ) {
Result result;
result.returnCode = git( { "tag", "-d", name }, projectDir, result.result );
diff --git a/src/tools/ecode/plugins/git/git.hpp b/src/tools/ecode/plugins/git/git.hpp
index 96a6bbab6..423315afb 100644
--- a/src/tools/ecode/plugins/git/git.hpp
+++ b/src/tools/ecode/plugins/git/git.hpp
@@ -380,6 +380,9 @@ class Git {
Result createTag( const std::string& name, const std::string& revision,
const std::string& message = "", const std::string& projectDir = "" );
+ Result pushTag( const std::string& name, const std::string& remote,
+ const std::string& projectDir = "" );
+
Result deleteTag( const std::string& name, const std::string& projectDir = "" );
Result deleteRemoteBranch( const std::string& remote, const std::string& branch,
diff --git a/src/tools/ecode/plugins/git/gitplugin.cpp b/src/tools/ecode/plugins/git/gitplugin.cpp
index 290e7d3f4..bb9178eee 100644
--- a/src/tools/ecode/plugins/git/gitplugin.cpp
+++ b/src/tools/ecode/plugins/git/gitplugin.cpp
@@ -2736,19 +2736,53 @@ void GitPlugin::addTag( const Git::Commit& commit ) {
name->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::WrapContent )
->setLayoutMargin( Rectf( 0, 4, 0, 4 ) )
->setParent( box->getTextEdit()->getParent() );
+ name->setHint( i18n( "git_tag_name_hint", "Tag name" ) );
name->toPosition( 1 );
- box->getTextEdit()->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::Fixed );
- box->getButtonOK()->setText( i18n( "git_add_tag", "Add Tag" ) );
- box->on( Event::OnConfirm, [this, box, name, commit]( const Event* ) {
- const std::string tag = name->getText().toUtf8();
+ auto* message = box->getTextEdit();
+ message->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::Fixed );
+ message->setHint( i18n( "git_tag_message_hint", "Annotated tag message (optional)" ) );
+ auto addTagBtn = box->getButtonOK();
+ addTagBtn->setText( i18n( "git_add_tag", "Add Tag" ) );
+ auto* addTagAndPushBtn = UIPushButton::New();
+ addTagAndPushBtn->setText( i18n( "git_add_tag_and_push", "Add Tag & Push" ) )
+ ->setLayoutMargin( Rectf( 8, 0, 0, 0 ) )
+ ->setParent( addTagBtn->getParent() );
+ box->getButtonCancel()->setLayoutMargin( {} )->toPosition( 0 );
+ addTagBtn->setLayoutMargin( Rectf( 8, 0, 0, 0 ) )->toPosition( 1 );
+ addTagAndPushBtn->toPosition( 2 );
+ addTagBtn->setEnabled( false );
+ addTagAndPushBtn->setEnabled( false );
+ name->on( Event::OnTextChanged, [name, addTagBtn, addTagAndPushBtn]( const Event* ) {
+ const bool enabled = !name->getText().empty();
+ addTagBtn->setEnabled( enabled );
+ addTagAndPushBtn->setEnabled( enabled );
+ } );
+ auto createTag = [this, box, name, message, commit]( bool push ) {
+ std::string tag = name->getText().toUtf8();
if ( tag.empty() )
return;
- const std::string message = box->getTextEdit()->getText().toUtf8();
+ std::string tagMessage = message->getText().toUtf8();
+ std::string repo = repoSelected();
+ std::string remote{ "origin" };
+ if ( const auto branch = getBranchFromRepoPath( repo );
+ branch && !branch->remote.empty() ) {
+ const size_t separator = branch->remote.find( '/' );
+ if ( separator != std::string::npos )
+ remote = branch->remote.substr( 0, separator );
+ }
box->closeWindow();
- runAsync( [this, tag, message,
- commit] { return mGit->createTag( tag, commit.hash, message, repoSelected() ); },
- false, true );
- } );
+ runAsync(
+ [git = mGit, tag = std::move( tag ), tagMessage = std::move( tagMessage ),
+ repo = std::move( repo ), remote = std::move( remote ), hash = commit.hash, push]() {
+ auto result = git->createTag( tag, hash, tagMessage, repo );
+ if ( result.success() && push )
+ return git->pushTag( tag, remote, repo );
+ return result;
+ },
+ false, true );
+ };
+ box->on( Event::OnConfirm, [createTag]( const Event* ) mutable { createTag( false ); } );
+ addTagAndPushBtn->onClick( [createTag]( const Event* ) mutable { createTag( true ); } );
box->setTitle( i18n( "git_add_tag", "Add Tag" ) );
box->setCloseShortcut( { KEY_ESCAPE, KEYMOD_NONE } )->center();
box->showWhenReady();