diff --git a/TODO.md b/TODO.md
index c600123ad95ab26189d3d8994ce179d29a7855c8..6deb750952eceb49fc9972bbc2e2752baab61c63 100644
--- a/TODO.md
+++ b/TODO.md
@@ -12,7 +12,6 @@
   - fix detecting last note duration in exercises/exams
   - randomly generated melodies have no rests yet, but see below for a reason
   - add an option to skip rests (pitch detection gaps) and treat their duration as previous note was longer
-  - manual adding/editing ties
   - finish tuner, functionality similar to Android one (show tuning, middle A freq)
   - level creator:
     - question page icon might change depends on is there single note or a melody
@@ -21,7 +20,6 @@
   - music XML import dialog, to select voice or staff if there are more, and so
   - exam summary - give more valuable info, wear it nicely
   - charts - show preview of entire melody, chart tip is not suitable for it
-  - charts - revert analyzing latest exercise
   - \[Taction\] add common method for creating key shortcuts
   - migrate on preferred 48000 sample rate (ogg files and audio methods). DO NOT forget to resize output samples length
 
diff --git a/changes b/changes
index 9f2f4786483b73eb026993e1f588062e49c2c44c..ca4b1499f8adbdf2f576ba96981b6e6c3427e066 100644
--- a/changes
+++ b/changes
@@ -1,6 +1,7 @@
 1.7.1 beta2
      - improved analysis charts (look and behavior)
      - added handy drawer with exam list and chart options
+     - notes with the same pitches can be tied by user
      - disabling level creator pages which are currently unused
      - added help topic selector on 'help page' with all the context
      - make controls look (check boxes, radios, sliders) consistent
diff --git a/src/libs/core/score/tscoreobject.cpp b/src/libs/core/score/tscoreobject.cpp
index 3f92fcdab081e5c914d946923847c03a0e423eb0..097fcaa244438c0685e52863a9c480c566a198a6 100644
--- a/src/libs/core/score/tscoreobject.cpp
+++ b/src/libs/core/score/tscoreobject.cpp
@@ -1083,6 +1083,12 @@ void TscoreObject::enableActions() {
     m_lowerAct = new Taction(tr("lower", "as such as flats lower note"), QStringLiteral("tipbg"), this);
     connect(m_lowerAct, &Taction::triggered, this, &TscoreObject::handleNoteAction);
     m_lowerAct->setShortcut(createQmlShortcut(m_qmlComponent, "\"@\""));
+
+    m_tieAct = new Taction(QGuiApplication::translate("ScoreToolbox", "tie",
+                                                      "To translate it properly, check please meaning of 'tie' in musical context."),
+                           QStringLiteral("tipbg"), this);
+    connect(m_tieAct, &Taction::triggered, this, &TscoreObject::checkTieOfSelected);
+    m_tieAct->setShortcut(createQmlShortcut(m_qmlComponent, "\"l\""));
   }
 }
 
@@ -1154,6 +1160,54 @@ void TscoreObject::handleNoteAction() {
   }
 }
 
+
+void TscoreObject::checkTieOfSelected() {
+  if (m_selectedItem && m_selectedItem->index() > 0) {
+    auto prevNote = m_segments[m_selectedItem->index() - 1];
+    auto n = *m_selectedItem->note();
+    if (m_selectedItem->note()->rtm.tie() > Trhythm::e_tieStart) { // disconnect
+        prevNote->disconnectTie(TnotePair::e_untiePrev);
+        n.rtm.setTie(n.rtm.tie() == Trhythm::e_tieEnd ? Trhythm::e_noTie : Trhythm::e_tieStart);
+        m_selectedItem->wrapper()->setNote(n);
+        emit m_selectedItem->hasTieChanged();
+        if (m_selectedItem->staff()->firstNote()->item() == m_selectedItem)
+          m_selectedItem->staff()->deleteExtraTie();
+    } else {
+        if (!m_selectedItem->note()->isRest() && m_selectedItem->note()->chromatic() == prevNote->note()->chromatic()) {
+          n.rtm.setTie(n.rtm.tie() == Trhythm::e_noTie ? Trhythm::e_tieEnd : Trhythm::e_tieCont);
+          m_selectedItem->wrapper()->setNote(n);
+          auto pn = *prevNote->note();
+          pn.rtm.setTie(pn.rtm.tie() == Trhythm::e_noTie ? Trhythm::e_tieStart : Trhythm::e_tieCont);
+          prevNote->setNote(pn);
+          emit m_selectedItem->hasTieChanged();
+          if (m_selectedItem->staff()->firstNote()->item() == m_selectedItem)
+            m_selectedItem->staff()->createExtraTie(m_selectedItem);
+        }
+    }
+    auto notesForAlterCheck = tieRange(prevNote->item());
+    bool fitStaff = false;
+    auto measureToRefresh = m_segments[notesForAlterCheck.x()]->item()->measure();
+    notesForAlterCheck.setX(m_segments[notesForAlterCheck.x()]->item()->measure()->firstNoteId());
+    notesForAlterCheck.setY(m_segments[notesForAlterCheck.y()]->item()->measure()->lastNoteId());
+    for (int i = notesForAlterCheck.x(); i <= notesForAlterCheck.y(); ++i) {
+      if (m_segments[i]->note()->note() == n.note()) {
+        fitStaff = true;
+        m_segments[i]->item()->updateAlter();
+      }
+      if (m_segments[i]->item()->measure() != measureToRefresh) {
+        measureToRefresh->refresh();
+        measureToRefresh = m_segments[i]->item()->measure();
+      }
+    }
+    measureToRefresh->refresh();
+    if (fitStaff) {
+      m_segments[notesForAlterCheck.x()]->item()->staff()->fit();
+      if (m_segments[notesForAlterCheck.y()]->item()->staff() != m_segments[notesForAlterCheck.x()]->item()->staff())
+        m_segments[notesForAlterCheck.y()]->item()->staff()->fit();
+    }
+  }
+}
+
 //#################################################################################################
 //###################              PROTECTED           ############################################
 //#################################################################################################
diff --git a/src/libs/core/score/tscoreobject.h b/src/libs/core/score/tscoreobject.h
index 80f9cea7ab9944acd760a898da2e4eb1871274f8..a5ad5785af9fcc6212ccb215692c82fac0a206e9 100644
--- a/src/libs/core/score/tscoreobject.h
+++ b/src/libs/core/score/tscoreobject.h
@@ -420,6 +420,7 @@ public:
   Taction* dotNoteAct() { return m_dotNoteAct; }
   Taction* riseAct() { return m_riseAct; }
   Taction* lowerAct() { return m_lowerAct; }
+  Taction* tieAct() { return m_tieAct; }
 
   Q_INVOKABLE void enableActions();
 
@@ -436,6 +437,15 @@ public:
 
   TclefOffset clefOffset() const { return m_clefOffset; }
 
+      /**
+       * Connects or disconnects selected note (if any) with previous one if their pitches are the same.
+       * Set/unset ties, emits @p hasTieChanged() to inform score toolbox.
+       * Checks alters of all affected notes (adding tie on measure beginning changes the rule of displaying alter)
+       * Fit staff if necessary.
+       * Adds/removes extra tie at the staff beginning when needed
+       */
+  Q_INVOKABLE void checkTieOfSelected();
+
 signals:
   void meterChanged();
 
@@ -703,6 +713,7 @@ private:
   Taction                          *m_insertNoteAct = nullptr;
   Taction                          *m_riseAct = nullptr;
   Taction                          *m_lowerAct = nullptr;
+  Taction                          *m_tieAct = nullptr;
 
 };
 
diff --git a/src/main/tmainscoreobject.cpp b/src/main/tmainscoreobject.cpp
index 5fc20f97b3f8ce6bfab79edb2f6ea9c2d824ea89..462769b48b0f860c09b9b58bfff78234eb081c75 100644
--- a/src/main/tmainscoreobject.cpp
+++ b/src/main/tmainscoreobject.cpp
@@ -146,7 +146,7 @@ void TmainScoreObject::setScoreObject(TscoreObject* scoreObj) {
   m_scoreActions << m_scoreObj->insertNoteAct() << m_scoreObj->deleteNoteAct() << m_scoreObj->clearScoreAct() << m_notesMenuAct;
   m_noteActions << m_scoreObj->riseAct() << m_scoreObj->lowerAct()
                 << m_scoreObj->wholeNoteAct() << m_scoreObj->halfNoteAct() << m_scoreObj->quarterNoteAct() << m_scoreObj->eighthNoteAct()
-                << m_scoreObj->sixteenthNoteAct() << m_scoreObj->restNoteAct() << m_scoreObj->dotNoteAct();
+                << m_scoreObj->sixteenthNoteAct() << m_scoreObj->restNoteAct() << m_scoreObj->dotNoteAct() << m_scoreObj->tieAct();
 
   connect(m_nextNoteAct, &Taction::triggered, [=]{
     if (!GLOB->isSingleNote()) {
diff --git a/src/qml/ScoreMenuContent.qml b/src/qml/ScoreMenuContent.qml
index a108587dc4c75cef90b95e11247e3625ac075cb8..7806db02f5c7fb17ee5952d4249cb071a07d486c 100644
--- a/src/qml/ScoreMenuContent.qml
+++ b/src/qml/ScoreMenuContent.qml
@@ -36,7 +36,7 @@ Tmenu {
     }
   }
 
-  property var rGlyphs: [ "#", "b", "C", "D", "E", "F", "G", "\ue109", "." ]
+  property var rGlyphs: [ "#", "b", "C", "D", "E", "F", "G", "\ue109", ".", "\ue18c" ]
   Loader { id: notesLoader; sourceComponent: notesComp; active: false }
   Component {
     id: notesComp
@@ -50,6 +50,7 @@ Tmenu {
           padding: 0
           width: menu.width
           contentItem: MenuButton {
+            id: mb
             action: modelData
             onClicked: close()
             Rectangle { width: parent.width; height: index === score.noteActions.length - 1 ? 0 : 1; color: activPal.text; y: parent.height - 1 }
@@ -58,6 +59,8 @@ Tmenu {
               color: activPal.text
               x: (Noo.fontSize() * 3.2 - width) / 2; anchors.verticalCenter: parent.verticalCenter
               font { pixelSize: Noo.fontSize() * 1.5; family: "nootka"; }
+              scale: GLOB.useAnimations && !mb.containsPress && mb.containsMouse ? 1.4 : 1.0
+              Behavior on scale { enabled: GLOB.useAnimations; NumberAnimation { duration: 150 }}
             }
           }
         }
diff --git a/src/qml/score/ControlButton.qml b/src/qml/score/ControlButton.qml
index 59f06a4a491e99b63c4b17b5a049010440f58a61..f853ce9616e997868c8f76a2f26320fe78d1f2fc 100644
--- a/src/qml/score/ControlButton.qml
+++ b/src/qml/score/ControlButton.qml
@@ -30,7 +30,7 @@ Rectangle {
 
   Text {
     id: txt
-    x: (factor * 2 - width) / 2
+    x: (cb.width - width) / 2
     height: factor * 3
     style: Text.Normal
     color: cb.enabled ? activPal.text : disdPal.text
diff --git a/src/qml/score/ScoreToolbox.qml b/src/qml/score/ScoreToolbox.qml
index 79d052084573955707035b1e4762eb606b28bf16..e6027549b219844f0b41b868bb033406107822fa 100644
--- a/src/qml/score/ScoreToolbox.qml
+++ b/src/qml/score/ScoreToolbox.qml
@@ -20,7 +20,7 @@ ControlBase {
 
   property string rhythmText: Noo.rhythmText(scoreObj.workRhythm)
   property bool triplet: false
-  property bool tie: false
+  property bool tie: scoreObj.selectedItem && scoreObj.selectedItem.hasTie
 
   // Accidentals
   property int selectedId: idArray[scoreObj.cursorAlter + 2]
@@ -87,7 +87,7 @@ ControlBase {
         Loader { // triplet
           id: tripLoad
           sourceComponent: ctrlButtonComp
-          onLoaded: { item.rhythm = 0; item.text = "\u0183"; item.enabled = false }
+          onLoaded: { item.rhythm = 0; item.text = " " /*"\u0183"*/ }
           Binding { target: tripLoad.item; property: "selected"; value: toolbox.triplet }
 //           Connections {
 //             target: tripLoad.item
@@ -108,17 +108,23 @@ ControlBase {
       }
 
       ControlButton { // tie
-        visible: false //score.meter !== Tmeter.NoMeter
+        visible: score.meter !== Tmeter.NoMeter
         anchors.horizontalCenter: parent.horizontalCenter
-        factor: toolbox.factor * 1.2
+        factor: toolbox.factor
         selected: toolbox.tie
-        height: factor * 1.5
-        yOffset: factor * -2.2
+        height: factor * 1.5; width: factor * 2.7
+        yOffset: factor * -2.3
         font { family: "nootka"; pointSize: factor * 3.6 }
         text: "\ue18c"
-//         onClicked: toolbox.tie = !selected
-        onEntered: hideTimer.stop()
-        onExited: hideTimer.restart()
+        onClicked: scoreObj.checkTieOfSelected()
+        onEntered: {
+          hideTimer.stop()
+          Noo.setStatusTip(qsTr("Tie - connect or disconnect selected note with previous one if both notes have the same pitch.") + "<br><b>(L)</b>", Item.Top)
+        }
+        onExited: {
+          hideTimer.restart()
+          Noo.setStatusTip("", Item.Top)
+        }
       }
 
       Rectangle { visible: scoreObj.enableTechnical; width: toolbox.width; height: 1; color: activPal.text }