From e2111edc6f906776fb107838c7d19c8ae7ad1005 Mon Sep 17 00:00:00 2001
From: SeeLook <SeeLook@localhost>
Date: Mon, 1 Jan 2018 19:56:36 +0100
Subject: [PATCH] Checking answer (partially), displaying results so added
 ResultTip.qml and all signals. Restore tresulttexts and textrans

---
 src/libs/core/CMakeLists.txt       |   6 +-
 src/libs/core/core.pro             |  30 ++--
 src/libs/core/exam/textrans.h      |  70 ++++++--
 src/libs/core/exam/tresulttext.cpp |  14 +-
 src/libs/core/exam/tresulttext.h   |  16 +-
 src/main/texamexecutor.cpp         | 247 ++++++++++++++---------------
 src/main/tmainscoreobject.cpp      |  10 ++
 src/main/tmainscoreobject.h        |   2 +
 src/main/ttiphandler.cpp           | 122 +++++++-------
 src/main/ttiphandler.h             |  41 +++--
 src/nootka.qrc                     |   1 +
 src/qml/exam/ExamExecutor.qml      |   4 +
 src/qml/exam/ResultTip.qml         |  55 +++++++
 13 files changed, 368 insertions(+), 250 deletions(-)
 create mode 100644 src/qml/exam/ResultTip.qml

diff --git a/src/libs/core/CMakeLists.txt b/src/libs/core/CMakeLists.txt
index e9343c910..06b5b4850 100644
--- a/src/libs/core/CMakeLists.txt
+++ b/src/libs/core/CMakeLists.txt
@@ -48,16 +48,14 @@ set(LIB_NOOTKACORE_SRC
   instruments/tbandoneonbg.cpp
   instruments/tsaxbg.cpp
 
-#   Android/tmobilemenu.cpp
-
   exam/tqatype.cpp
   exam/tqaunit.cpp
   exam/tqagroup.cpp
   exam/tattempt.cpp
   exam/tlevel.cpp
   exam/texam.cpp
-#   exam/textrans.h
-#   exam/tresulttext.cpp
+  exam/textrans.h
+  exam/tresulttext.cpp
 )
 
 
diff --git a/src/libs/core/core.pro b/src/libs/core/core.pro
index 9b1c06f9d..5a6806dc3 100644
--- a/src/libs/core/core.pro
+++ b/src/libs/core/core.pro
@@ -15,13 +15,13 @@ SOURCES +=  tcolor.cpp\
             tnootkaqml.cpp\
             taction.cpp\
           \
-             exam/tattempt.cpp\
-             exam/texam.cpp\
-             exam/tlevel.cpp\
-             exam/tqagroup.cpp\
-             exam/tqatype.cpp\
-             exam/tqaunit.cpp\
-#             exam/tresulttext.cpp\
+            exam/tattempt.cpp\
+            exam/texam.cpp\
+            exam/tlevel.cpp\
+            exam/tqagroup.cpp\
+            exam/tqatype.cpp\
+            exam/tqaunit.cpp\
+            exam/tresulttext.cpp\
           \
             music/tchunk.cpp\
             music/tclef.cpp\
@@ -71,14 +71,14 @@ HEADERS  += nootkaconfig.h\
             tnootkaqml.h\
             taction.h\
           \
-             exam/tattempt.h\
-             exam/texam.h\
-             exam/textrans.h\
-             exam/tlevel.h\
-             exam/tqagroup.h\
-             exam/tqatype.h\
-             exam/tqaunit.h\
-#             exam/tresulttext.h\
+            exam/tattempt.h\
+            exam/texam.h\
+            exam/textrans.h\
+            exam/tlevel.h\
+            exam/tqagroup.h\
+            exam/tqatype.h\
+            exam/tqaunit.h\
+            exam/tresulttext.h\
           \
             music/tchunk.h\
             music/tclef.h\
diff --git a/src/libs/core/exam/textrans.h b/src/libs/core/exam/textrans.h
index 7d3f4b3a6..920860757 100644
--- a/src/libs/core/exam/textrans.h
+++ b/src/libs/core/exam/textrans.h
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2014 by Tomasz Bojczuk                                  *
+ *   Copyright (C) 2014-2018 by Tomasz Bojczuk                             *
  *   seelook@gmail.com                                                     *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
@@ -35,60 +35,96 @@ public:
   TexTrans() {};
 
 
+   /**
+    * Average time taken to answer
+    */
 static const QString averAnsverTimeTxt() {
     return QApplication::translate("TexamView", "Average time taken to answer");
-  } /** Average time taken to answer */
+  }
 
 static const QString inSecondsTxt() { return QApplication::translate("TexamView", "[in seconds]"); } // [in seconds]
 static const QString totalTimetxt() { return QApplication::translate("TexamView", "Total time"); } // Total time
 static const QString effectTxt() { return QApplication::translate("TexamView", "Effectiveness"); } // Effectiveness
 
+    /**
+     * Number of correct answers
+     */
 static const QString corrAnswersNrTxt() {
     return QApplication::translate("TexamView", "Number of correct answers");
-  } /** Number of correct answers */
+  }
 
 static const QString reactTimeTxt() { return QApplication::translate("TexamView", "Time for an answer"); } // Time for an answer
 
 static const QString mistakesNrTxt() { return QApplication::translate("TexamView", "Number of mistakes"); } // Number of mistakes
 
+    /**
+     * Number of not bad answers
+     */
 static const QString halfMistakenTxt() {
     return QApplication::translate("TexamView", "'Not bad' answers");
-  }         /** Number of not bad answers */
+  }
 
+  /**
+   * (counted as half of a mistake)
+   */
 static const QString halfMistakenAddTxt() {
     return QApplication::translate("TexamView", "(counted as half of a mistake)");
-  } /** (counted as half of a mistake) */
+  }
 
 
 static const QString examFilterTxt() { return QApplication::translate("TstartExamDlg", "Exam results")  + " (*.noo)" ; }
 
+    /**
+     * Load an exam file
+     */
 static const QString loadExamFileTxt() {
     return QApplication::translate("TstartExamDlg", "Load an exam file");
-  } /** Load an exam file */
+  }
 
+    /**
+     * Get more levels <a>from Nootka home page</a>
+     */
 static QString moreLevelLinkTxt() {
     return QApplication::translate(
       "levelSettings" ,"Get more levels <a href=\"%1\">from Nootka home page</a>")
           .arg("http://www.nootka.sf.net/index.php?C=down#levels");
-  } /** Get more levels <a>from Nootka home page</a> */
-
-static QString playMelodyTxt() { return QApplication::translate("Texam", "play melody"); } /** play melody */
-
-static QString writeMelodyTxt() { return QApplication::translate("Texam", "write melody"); } /** write melody */
-
-static QString attemptTxt() { return QApplication::translate("Texam", "attempt"); } /** attempt */
-
+  }
+
+    /**
+     * play melody
+     */
+static QString playMelodyTxt() { return QApplication::translate("Texam", "play melody"); }
+
+    /**
+     * write melody
+     */
+static QString writeMelodyTxt() { return QApplication::translate("Texam", "write melody"); }
+
+    /**
+     * attempt
+     */
+static QString attemptTxt() { return QApplication::translate("Texam", "attempt"); }
+
+    /**
+     * 7 attempts (or other number given as a parameter)
+     */
 static QString attemptsTxt(int aCount) {
     return QApplication::translate("Texam", "%n attempt(s)", "like: '1 attempt' or '121 attempts'", aCount);
-  } /**  7 attempts (or other number given as a parameter) */
+  }
 
+    /**
+     * Play a melody written in a score
+     */
 static QString playDescTxt() {
     return QApplication::translate("Texam", "Play a melody written in a score");
-  } /** Play a melody written in a score */
+  }
 
+    /**
+     * Listen to a melody and write it on a score
+     */
 static QString writeDescTxt() {
     return QApplication::translate("Texam", "Listen to a melody and write it on a score");
-  } /** Listen to a melody and write it on a score */
+  }
 
 };
 
diff --git a/src/libs/core/exam/tresulttext.cpp b/src/libs/core/exam/tresulttext.cpp
index cbf208b11..8359ced60 100644
--- a/src/libs/core/exam/tresulttext.cpp
+++ b/src/libs/core/exam/tresulttext.cpp
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2015-2016 by Tomasz Bojczuk                             *
+ *   Copyright (C) 2015-2018 by Tomasz Bojczuk                             *
  *   seelook@gmail.com                                                     *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
@@ -23,7 +23,9 @@
 #include <QtGui/qcolor.h>
 
 
-    /** Adds comma and space ', ' (',<br>' on Android) to not empty string or returns the same. */
+    /**
+     * Adds comma and space ', ' (',<br>' on Android) to not empty string or returns the same.
+     */
 void addSpaceToNotEmpty(QString& txt) {
   if (!txt.isEmpty()) {
 #if defined (Q_OS_ANDROID)
@@ -45,12 +47,8 @@ void newLineText(QString& txt, const QString& newText) {
 }
 
 
-QString wasAnswerOKtext(TQAunit* answer, const QColor& textColor, int fontSize, int attempt) {
+QString wasAnswerOKtext(TQAunit* answer, int attempt) {
   QString txt;
-  if (fontSize != -1)
-      txt = QString("<span style=\"color: %1; font-size: %2px;\">").arg(textColor.name()).arg(fontSize);
-  else
-      txt = QString("<span style=\"color: %1;\">").arg(textColor.name());
   TQAunit curQ;
   if (answer->melody() && attempt > 0 && attempt <= answer->attemptsCount())
     curQ.setMistake(answer->attempt(attempt - 1)->summary());
@@ -94,7 +92,7 @@ QString wasAnswerOKtext(TQAunit* answer, const QColor& textColor, int fontSize,
           }
           txt += misMes;
       }
-  txt += QLatin1String("</span><br>");
+//   txt += QLatin1String("</span><br>");
   return txt;
 
 }
diff --git a/src/libs/core/exam/tresulttext.h b/src/libs/core/exam/tresulttext.h
index 6955c72f6..4c7b6ee0d 100644
--- a/src/libs/core/exam/tresulttext.h
+++ b/src/libs/core/exam/tresulttext.h
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2015 by Tomasz Bojczuk                                  *
+ *   Copyright (C) 2015-2018 by Tomasz Bojczuk                             *
  *   seelook@gmail.com                                                     *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
@@ -21,15 +21,17 @@
 #define TRESULTTEXT_H
 
 #include <nootkacoreglobal.h>
-#include <QString>
+#include <QtCore/qstring.h>
 
 class TQAunit;
 class QColor;
 
-    /** Returns HTML formatted text with answer details.
-    * If @p fontSize remains default - default @p fontSize is taken.
-    * When @p attempt is bigger than 0 (and answer was a melody of course)
-    * The summary of that attempt is prepared.  */
-NOOTKACORE_EXPORT QString wasAnswerOKtext(TQAunit* answer, const QColor& textColor, int fontSize = -1, int attempt = 0);
+    /**
+     * Returns HTML formatted text with answer details.
+     * If @p fontSize remains default - default @p fontSize is taken.
+     * When @p attempt is bigger than 0 (and answer was a melody of course)
+     * The summary of that attempt is prepared.
+     */
+NOOTKACORE_EXPORT QString wasAnswerOKtext(TQAunit* answer, int attempt = 0);
 
 #endif // TRESULTTEXT_H
diff --git a/src/main/texamexecutor.cpp b/src/main/texamexecutor.cpp
index a4974b989..41f788609 100755
--- a/src/main/texamexecutor.cpp
+++ b/src/main/texamexecutor.cpp
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2011-2017 by Tomasz Bojczuk                             *
+ *   Copyright (C) 2011-2018 by Tomasz Bojczuk                             *
  *   seelook@gmail.com                                                     *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
@@ -33,7 +33,6 @@
 // #include <exam/textrans.h>
 #include <exam/tattempt.h>
 #include "texamhelp.h"
-// #include <help/texpertanswerhelp.h>
 #include <taudioparams.h>
 #include <texamparams.h>
 #include <tscoreparams.h>
@@ -580,143 +579,143 @@ void TexamExecutor::checkAnswer(bool showResults) {
   if (m_exam->melodies() && SOUND->melodyIsPlaying())
     SOUND->stopPlaying();
 
-//   if (!GLOB->E->autoNextQuest || m_exercise)
-//       TOOLBAR->startExamAct->setDisabled(false);
+  if (!GLOB->E->autoNextQuest || m_exercise)
+    m_stopExamAct->setEnabled(true);
   m_isAnswered = true;
 // Let's check
-//   Tnote questNote, answNote, userNote; // example note & returned note
-// // At first we determine what has to be checked
-//   if (!curQ->melody()) {
-//     questNote = curQ->qa.note;
-//     if (curQ->answerAsNote()) {
-//         if (m_level.manualKey) {
-//             if (SCORE->keySignature().value() != curQ->key.value())
-//                 curQ->setMistake(TQAunit::e_wrongKey);
-//         }
-//         if (curQ->questionAsNote())
-//             questNote = curQ->qa_2.note;
-//         answNote = SCORE->getNote(0);
-//     }
-//     if (curQ->answerAsName()) {
-//         if (curQ->questionAsName())
-//             questNote = curQ->qa_2.note;
-//         m_prevNoteIfName = NOTENAME->getNoteName(); // store note to restore it if will be repeated
-//         answNote = NOTENAME->getNoteName();
-//     }
-//     userNote = answNote;
-//     if (curQ->answerAsSound()) {
-//         answNote = SOUND->note();
+  Tnote questNote, answNote, userNote; // example note & returned note
+// At first we determine what has to be checked
+  if (!curQ->melody()) {
+    questNote = curQ->qa.note;
+    if (curQ->answerAsNote()) {
+        if (m_level.manualKey) {
+            if (MAIN_SCORE->keySignatureValue() != curQ->key.value())
+              curQ->setMistake(TQAunit::e_wrongKey);
+        }
+        if (curQ->questionAsNote())
+            questNote = curQ->qa_2.note;
+        answNote = MAIN_SCORE->getNote(0);
+    }
+    if (curQ->answerAsName()) {
+        if (curQ->questionAsName())
+            questNote = curQ->qa_2.note;
+        m_prevNoteIfName = NOTENAME->note(); // store note to restore it if will be repeated
+        answNote = NOTENAME->note();
+    }
+    userNote = answNote;
+    if (curQ->answerAsSound()) {
+        answNote = SOUND->note();
 //         if ((TintonationView::Eaccuracy)m_level.intonation != TintonationView::e_noCheck) {
 //             if (TnoteStruct(Tnote(), SOUND->pitch()).inTune(TintonationView::getThreshold(m_level.intonation)))
 //                 curQ->setMistake(TQAunit::e_wrongIntonation);
 //         }
-//     }
-//   }
-// // Now we can check
-//   if (curQ->answerAsFret()) { // 1. Comparing positions
-//       TfingerPos answPos, questPos;
+    }
+  }
+// Now we can check
+  if (curQ->answerAsFret()) { // 1. Comparing positions
+      TfingerPos answPos, questPos;
 //       answPos = INSTRUMENT->getfingerPos();
-//       if (curQ->questionAsFret()) { 
-//         if (answPos == curQ->qa.pos) { // check has not user got answer the same as question position
-//           curQ->setMistake(TQAunit::e_wrongPos);
-//           qDebug("Cheater!");
-//         } else 
-//           questPos = curQ->qa_2.pos;
-//       } else
-//         questPos = curQ->qa.pos;
-//       if (questPos != answPos && curQ->isCorrect()) { // if no cheater give him a chance
-//         QList <TfingerPos> tmpPosList; // Maybe hi gave correct note but on incorrect string only
-//         m_supp->getTheSamePosNoOrder(answPos, tmpPosList); // get other positions
-//         bool otherPosFound = false;
-//         for (int i = 0; i < tmpPosList.size(); i++) {
-//             if (tmpPosList[i] == questPos) { // and compare it with expected
-//               otherPosFound = true;
-//               break;
-//             }
-//         }
-//         if (otherPosFound) {
-//           if (m_level.showStrNr || answPos.fret() < m_level.loFret || answPos.fret() > m_level.hiFret)
-//             curQ->setMistake(TQAunit::e_wrongString); // check the level settings and mark as wrong string when deserve
-//         } else
-//             curQ->setMistake(TQAunit::e_wrongPos);
-//       }
-//   } else {
-//       if (curQ->melody()) { // 2. or checking melodies
-//           curQ->setMistake(TQAunit::e_correct); // reset an answer
-//           if (curQ->answerAsNote()) { // dictation
-//             Tmelody answMelody;
+      if (curQ->questionAsFret()) { 
+        if (answPos == curQ->qa.pos) { // check has not user got answer the same as question position
+          curQ->setMistake(TQAunit::e_wrongPos);
+          qDebug("Cheater!");
+        } else 
+          questPos = curQ->qa_2.pos;
+      } else
+        questPos = curQ->qa.pos;
+      if (questPos != answPos && curQ->isCorrect()) { // if no cheater give him a chance
+        QList <TfingerPos> tmpPosList; // Maybe hi gave correct note but on incorrect string only
+        m_supp->getTheSamePosNoOrder(answPos, tmpPosList); // get other positions
+        bool otherPosFound = false;
+        for (int i = 0; i < tmpPosList.size(); i++) {
+            if (tmpPosList[i] == questPos) { // and compare it with expected
+              otherPosFound = true;
+              break;
+            }
+        }
+        if (otherPosFound) {
+          if (m_level.showStrNr || answPos.fret() < m_level.loFret || answPos.fret() > m_level.hiFret)
+            curQ->setMistake(TQAunit::e_wrongString); // check the level settings and mark as wrong string when deserve
+        } else
+            curQ->setMistake(TQAunit::e_wrongPos);
+      }
+  } else {
+      if (curQ->melody()) { // 2. or checking melodies
+          curQ->setMistake(TQAunit::e_correct); // reset an answer
+          if (curQ->answerAsNote()) { // dictation
+            Tmelody answMelody;
 //             SCORE->getMelody(&answMelody);
-//             m_supp->compareMelodies(curQ->melody(), &answMelody, curQ->lastAttempt());
-//           } else { // playing a score
-//             m_supp->compareMelodies(curQ->melody(), m_melody->listened(), curQ->lastAttempt());
-//           }
-//           int goodAllready = 0, notBadAlready = 0, wrongAlready = 0;
-//           for (int i = 0; i < curQ->lastAttempt()->mistakes.size(); ++i) { // setting mistake type in TQAunit
-//             if (curQ->lastAttempt()->mistakes[i] == TQAunit::e_correct) {
-//               goodAllready++;
-//               continue; // it was correct - skip
-//             }
-//             if (curQ->lastAttempt()->mistakes[i] & TQAunit::e_wrongNote) {
-//               wrongAlready++;
-//             } else // or 'not bad'
-//                 notBadAlready++;
-//           }
-//           if (goodAllready == curQ->melody()->length()) { // all required notes are correct
-//               curQ->setMistake(TQAunit::e_correct); // even if user put them more and effect. is poor
-// //               qDebug() << "Melody is correct";
-//           } else if (goodAllready + notBadAlready == curQ->melody()->length()) { // add committed mistakes of last attempt
-//               curQ->setMistake(curQ->lastAttempt()->summary()); // or 'not bad'
-// //               qDebug() << "Melody is not bad" << curQ->mistake();
-//           } else if (goodAllready + notBadAlready >= curQ->melody()->length() * 0.7) { // at least 70% notes answered properly
-// //             qDebug() << "Melody has little notes";
-//             if (curQ->lastAttempt()->effectiveness() >= 50.0) { // and effectiveness is sufficient
-//                 curQ->setMistake(curQ->lastAttempt()->summary());
-//                 curQ->setMistake(TQAunit::e_littleNotes); // but less notes than required
-// //                 qDebug() << "... and sufficient effectiveness";
-//             } else { // or effectiveness is too poor
-//                 curQ->setMistake(TQAunit::e_veryPoor);
-// //                 qDebug() << "... but very poor effectiveness" << curQ->lastAttempt()->effectiveness();
-//             }
-//           } else {
-//               curQ->setMistake(TQAunit::e_wrongNote);
-// //               qDebug() << "Simply wrong answer";
-//           }
-//           if (m_level.manualKey && !curQ->isWrong()) {
-//             if (SCORE->keySignature().value() != curQ->key.value())
-//                 curQ->setMistake(TQAunit::e_wrongKey);
-//           }
-//           // Another case is poor or very poor effectiveness but it is obtained after effect. update in sumarizeAnswer()
-//       } else { // 3. or checking are the notes the same
-//           m_supp->checkNotes(curQ, questNote, answNote, m_answRequire.octave, m_answRequire.accid);
-//           if (!m_answRequire.accid && curQ->isCorrect() && (curQ->answerAsNote() || curQ->answerAsName())) {
-//       // Save user given note when it is correct and accidental was not forced to respect kind of accidental
-//             if (curQ->questionAs == curQ->answerAs)
-//               curQ->qa_2.note = userNote;
-//             else
-//               curQ->qa.note = userNote;
-//           }
-//       }
-//   }
-//   m_penalty->checkAnswer();
-//   
-//   disableWidgets();
-//   bool autoNext = GLOB->E->autoNextQuest;
-//   if (GLOB->E->afterMistake == TexamParams::e_stop && !curQ->isCorrect())
-//       autoNext = false; // when mistake and e_stop - the same like autoNext = false;
-//     
-//   if (showResults) {
-//       m_tipHandler->resultTip(curQ); // tip duration is calculated by itself (inside resultTip() method)
+            m_supp->compareMelodies(curQ->melody(), &answMelody, curQ->lastAttempt());
+          } else { // playing a score
+            m_supp->compareMelodies(curQ->melody(), m_melody->listened(), curQ->lastAttempt());
+          }
+          int goodAllready = 0, notBadAlready = 0, wrongAlready = 0;
+          for (int i = 0; i < curQ->lastAttempt()->mistakes.size(); ++i) { // setting mistake type in TQAunit
+            if (curQ->lastAttempt()->mistakes[i] == TQAunit::e_correct) {
+              goodAllready++;
+              continue; // it was correct - skip
+            }
+            if (curQ->lastAttempt()->mistakes[i] & TQAunit::e_wrongNote) {
+              wrongAlready++;
+            } else // or 'not bad'
+                notBadAlready++;
+          }
+          if (goodAllready == curQ->melody()->length()) { // all required notes are correct
+              curQ->setMistake(TQAunit::e_correct); // even if user put them more and effect. is poor
+//               qDebug() << "Melody is correct";
+          } else if (goodAllready + notBadAlready == curQ->melody()->length()) { // add committed mistakes of last attempt
+              curQ->setMistake(curQ->lastAttempt()->summary()); // or 'not bad'
+//               qDebug() << "Melody is not bad" << curQ->mistake();
+          } else if (goodAllready + notBadAlready >= curQ->melody()->length() * 0.7) { // at least 70% notes answered properly
+//             qDebug() << "Melody has little notes";
+            if (curQ->lastAttempt()->effectiveness() >= 50.0) { // and effectiveness is sufficient
+                curQ->setMistake(curQ->lastAttempt()->summary());
+                curQ->setMistake(TQAunit::e_littleNotes); // but less notes than required
+//                 qDebug() << "... and sufficient effectiveness";
+            } else { // or effectiveness is too poor
+                curQ->setMistake(TQAunit::e_veryPoor);
+//                 qDebug() << "... but very poor effectiveness" << curQ->lastAttempt()->effectiveness();
+            }
+          } else {
+              curQ->setMistake(TQAunit::e_wrongNote);
+//               qDebug() << "Simply wrong answer";
+          }
+          if (m_level.manualKey && !curQ->isWrong()) {
+            if (MAIN_SCORE->keySignatureValue() != curQ->key.value())
+              curQ->setMistake(TQAunit::e_wrongKey);
+          }
+          // Another case is poor or very poor effectiveness but it is obtained after effect. update in sumarizeAnswer()
+      } else { // 3. or checking are the notes the same
+          m_supp->checkNotes(curQ, questNote, answNote, m_answRequire.octave, m_answRequire.accid);
+          if (!m_answRequire.accid && curQ->isCorrect() && (curQ->answerAsNote() || curQ->answerAsName())) {
+      // Save user given note when it is correct and accidental was not forced to respect kind of accidental
+            if (curQ->questionAs == curQ->answerAs)
+              curQ->qa_2.note = userNote;
+            else
+              curQ->qa.note = userNote;
+          }
+      }
+  }
+  m_penalty->checkAnswer();
+
+  disableWidgets();
+  bool autoNext = GLOB->E->autoNextQuest;
+  if (GLOB->E->afterMistake == TexamParams::e_stop && !curQ->isCorrect())
+      autoNext = false; // when mistake and e_stop - the same like autoNext = false;
+
+  if (showResults) {
+      m_tipHandler->resultTip(curQ); // tip duration is calculated by itself (inside resultTip() method)
 //       if ((!m_exercise || (m_exercise && curQ->isCorrect())) && !autoNext)
 //         m_tipHandler->whatNextTip(curQ->isCorrect());
-//       if (!autoNext) {
+      if (!autoNext) {
 //         if (!curQ->isCorrect() && !m_exercise && !curQ->melody())
 //             TOOLBAR->addAction(TOOLBAR->prevQuestAct);
 //         if (!curQ->isCorrect() && curQ->melody())
 //           TOOLBAR->addAction(TOOLBAR->attemptAct);
 //         TOOLBAR->addAction(TOOLBAR->nextQuestAct);
-//       }
-//   }
-// 
+      }
+  }
+
 //   markAnswer(curQ);
 //   int waitTime = GLOB->E->questionDelay;
 //   if (m_melody) // increase minimal delay before next question for melodies to 500ms
diff --git a/src/main/tmainscoreobject.cpp b/src/main/tmainscoreobject.cpp
index 8db6753bc..45ad035ed 100644
--- a/src/main/tmainscoreobject.cpp
+++ b/src/main/tmainscoreobject.cpp
@@ -130,8 +130,18 @@ void TmainScoreObject::clearScore() {
   m_scoreObj->setBgColor(qApp->palette().base().color());
 }
 
+
 void TmainScoreObject::setKeySignature(const TkeySignature& key) { m_scoreObj->setKeySignature(static_cast<int>(key.value())); }
 
+char TmainScoreObject::keySignatureValue() {
+  return static_cast<char>(m_scoreObj->keySignature());
+}
+
+
+Tnote TmainScoreObject::getNote(int id) {
+  return m_scoreObj->noteAt(id);
+}
+
 
 void TmainScoreObject::askQuestion(Tmelody* mel) {
   m_scoreObj->setBgColor(scoreBackgroundColor(GLOB->EquestionColor, 20));
diff --git a/src/main/tmainscoreobject.h b/src/main/tmainscoreobject.h
index f8a05d394..0b0a4ab1a 100644
--- a/src/main/tmainscoreobject.h
+++ b/src/main/tmainscoreobject.h
@@ -89,6 +89,8 @@ public:
   void setReadOnly(bool ro);
   void clearScore();
   void setKeySignature(const TkeySignature& key);
+  char keySignatureValue();
+  Tnote getNote(int id);
 
 // exam/exercise related
   void askQuestion(const Tnote& note, char realStr = 0);
diff --git a/src/main/ttiphandler.cpp b/src/main/ttiphandler.cpp
index 2a27cc278..5dc5e025d 100644
--- a/src/main/ttiphandler.cpp
+++ b/src/main/ttiphandler.cpp
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2012-2017 by Tomasz Bojczuk                             *
+ *   Copyright (C) 2012-2018 by Tomasz Bojczuk                             *
  *   seelook@gmail.com                                                     *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
@@ -34,6 +34,7 @@
 #include "tnameitem.h"
 #include <tsound.h>
 #include <tpath.h>
+#include <texamparams.h>
 #if defined (Q_OS_ANDROID)
   #include <tmtr.h>
 #else
@@ -137,7 +138,7 @@ void TtipHandler::setTipPos(const QPointF& p) {
 }
 
 
-//void Tcanvas::setStatusMessage(const QString& text, int duration) {
+//void TtipHandler::setStatusMessage(const QString& text, int duration) {
 //#if defined (Q_OS_ANDROID)
 //  tMessage->setMessage(text, duration);
 //#else
@@ -159,49 +160,41 @@ int TtipHandler::bigFont() {
 }
 
 
-//void Tcanvas::resultTip(TQAunit* answer, int time) {
-//  clearConfirmTip();
-//  clearResultTip();
-//  clearTryAgainTip();
-
-//  bool autoNext = Tcore::gl()->E->autoNextQuest;
-//  if (Tcore::gl()->E->afterMistake == TexamParams::e_stop && !answer->isCorrect())
-//      autoNext = false; // when mistake and e_stop - the same like autoNext = false;
-//  if (autoNext) { // determine time of displaying
-//    if (answer->isCorrect() || Tcore::gl()->E->afterMistake == TexamParams::e_continue)
-//      time = 2500; // hard-coded
-//    else
-//      time = Tcore::gl()->E->mistakePreview; // user defined wait time
-//  }
-
-//#if defined (Q_OS_ANDROID)
-//  int bf = qMin(Tmtr::shortScreenSide() / 10, qRound(Tmtr::fingerPixels() * 2.0));
-//#else
-//  int bf = bigFont();
-//#endif
-//  m_resultTip = new TgraphicsTextTip(wasAnswerOKtext(answer, TexecutorSupply::answerColor(answer->mistake()), bf));
-//  m_scene->addItem(m_resultTip);
-//  m_resultTip->setZValue(100);
-
+void TtipHandler::resultTip(TQAunit* answer, int time) {
+  m_timerToConfirm->stop();
+  clearCanvas();
+
+ bool autoNext = GLOB->E->autoNextQuest;
+ if (GLOB->E->afterMistake == TexamParams::e_stop && !answer->isCorrect())
+     autoNext = false; // when mistake and e_stop - the same like autoNext = false;
+ if (autoNext) { // determine time of displaying
+   if (answer->isCorrect() || GLOB->E->afterMistake == TexamParams::e_continue)
+     time = 2500; // hard-coded
+   else
+     time = GLOB->E->mistakePreview; // user defined wait time
+ }
+
+  emit showResultTip(wasAnswerOKtext(answer), TexecutorSupply::answerColor(answer->mistake()));
+ 
 //  if (answer->isNotSoBad())
 //    m_resultTip->setScale(m_scale);
 //  else
 //    m_resultTip->setScale(m_scale * 1.2);
 //  setResultPos();
-//  if (Tcore::gl()->E->showWrongPlayed && Tcore::gl()->E->showWrongPlayed && !answer->melody() &&
+//  if (GLOB->E->showWrongPlayed && GLOB->E->showWrongPlayed && !answer->melody() &&
 //      answer->answerAsSound() && !answer->isCorrect() && SOUND->note().note)
 //          detectedNoteTip(SOUND->note()); // In exercise mode display detected note when it was incorrect
-//  if (time)
-//      QTimer::singleShot(time, this, SLOT(clearResultTip()));
-//}
+  if (time)
+    QTimer::singleShot(time, [=]{ emit destroyResultTip(); });
+}
 
 
-//QString Tcanvas::detectedText(const QString& txt) {
-//  return QString("<span style=\"color: %1;\"><big>").arg(Tcore::gl()->EquestionColor.name()) + txt + QLatin1String("</big></span>");
+//QString TtipHandler::detectedText(const QString& txt) {
+//  return QString("<span style=\"color: %1;\"><big>").arg(GLOB->EquestionColor.name()) + txt + QLatin1String("</big></span>");
 //}
 
 
-//void Tcanvas::detectedNoteTip(const Tnote& note) {
+//void TtipHandler::detectedNoteTip(const Tnote& note) {
 //  Tnote n = note;
 //  if (n.isValid())
 //    setStatusMessage(QLatin1String("<table valign=\"middle\" align=\"center\"><tr><td> ") +
@@ -210,9 +203,9 @@ int TtipHandler::bigFont() {
 //}
 
 
-//void Tcanvas::tryAgainTip(int time) {
+//void TtipHandler::tryAgainTip(int time) {
 //  m_tryAgainTip = new TgraphicsTextTip(QString("<span style=\"color: %1; font-size: %2px;\">")
-//      .arg(Tcore::gl()->EquestionColor.name()).arg(bigFont()) + tr("Try again!") + "</span>");
+//      .arg(GLOB->EquestionColor.name()).arg(bigFont()) + tr("Try again!") + "</span>");
 //  m_scene->addItem(m_tryAgainTip);
 //  m_tryAgainTip->setZValue(100);
 //  m_tryAgainTip->setScale(m_scale);
@@ -245,7 +238,7 @@ void TtipHandler::startTip() {
 }
 
 
-//void Tcanvas::certificateTip() {
+//void TtipHandler::certificateTip() {
 //  if (m_certifyTip)
 //    return;
 
@@ -259,7 +252,7 @@ void TtipHandler::startTip() {
 //}
 
 
-//void Tcanvas::whatNextTip(bool isCorrect, bool toCorrection) {
+//void TtipHandler::whatNextTip(bool isCorrect, bool toCorrection) {
 //  delete m_questionTip;
 //  clearWhatNextTip();
 //#if defined (Q_OS_ANDROID)
@@ -288,7 +281,7 @@ void TtipHandler::startTip() {
 //      });
 //  }
 //  if (toCorrection) {
-//    m_correctTip = new ThackedTouchTip(getTipText("correct", "Correct"), Tcore::gl()->EanswerColor);
+//    m_correctTip = new ThackedTouchTip(getTipText("correct", "Correct"), GLOB->EanswerColor);
 //    m_scene->addItem(m_correctTip);
 //    m_correctTip->setFont(smalTipFont(m_view));
 //    connect(m_correctTip, &ThackedTouchTip::clicked, [=] {
@@ -336,11 +329,14 @@ void TtipHandler::startTip() {
 
 
 void TtipHandler::confirmTip(int time) {
+  if (!m_confirmTipOn) {
 #if defined (Q_OS_ANDROID)
- showConfirmTip();
+    showConfirmTip();
 #else
- m_timerToConfirm->start(time + 1); // add 1 to show it immediately when time = 0
+    m_timerToConfirm->start(time + 1); // add 1 to show it immediately when time = 0
 #endif
+    m_confirmTipOn = true;
+  }
 }
 
 
@@ -357,7 +353,7 @@ void TtipHandler::showConfirmTip() {
 }
 
 
-//void Tcanvas::playMelodyAgainMessage() {
+//void TtipHandler::playMelodyAgainMessage() {
 //#if defined (Q_OS_ANDROID)
 //  tMessage->setMessage(detectedText(tr("Select any note to play it again.")), 3000);
 //#else
@@ -367,6 +363,7 @@ void TtipHandler::showConfirmTip() {
 
 
 void TtipHandler::questionTip() {
+  emit destroyResultTip();
   QString br = QStringLiteral("<br>");
   QString sp = QStringLiteral(" ");
   QString questText;
@@ -496,7 +493,7 @@ void TtipHandler::questionTip() {
 }
 
 
-//void Tcanvas::outOfTuneTip(float pitchDiff) {
+//void TtipHandler::outOfTuneTip(float pitchDiff) {
 //  if (m_outTuneTip)
 //    return;
 //  QString tuneText;
@@ -508,7 +505,7 @@ void TtipHandler::questionTip() {
 //    tooLow = false;
 //  }
 //  m_outTuneTip = new TgraphicsTextTip(QString("<span style=\"color: %1; font-size: %2px;\">")
-//      .arg(Tcore::gl()->EanswerColor.name()).arg(bigFont()) + tuneText + "</span>");
+//      .arg(GLOB->EanswerColor.name()).arg(bigFont()) + tuneText + "</span>");
 //  m_scene->addItem(m_outTuneTip);
 //  m_outTuneTip->setZValue(100);
 //  m_outTuneTip->setScale(m_scale);
@@ -517,12 +514,12 @@ void TtipHandler::questionTip() {
 //}
 
 
-//void Tcanvas::melodyCorrectMessage() {
+//void TtipHandler::melodyCorrectMessage() {
 //  if (m_melodyCorrectMessage)
 //    return;
 
 //  m_melodyCorrectMessage = true;
-//  QString message = QString("<span style=\"color: %1;\"><big>").arg(Tcore::gl()->EanswerColor.name()) +
+//  QString message = QString("<span style=\"color: %1;\"><big>").arg(GLOB->EanswerColor.name()) +
 //                    tr("Click incorrect notes to see<br>and to listen to them corrected.") + QLatin1String("</big></span>");
 //#if defined (Q_OS_ANDROID)
 //  tMessage->setMessage(message, 10000); // temporary message on a tip
@@ -534,13 +531,13 @@ void TtipHandler::questionTip() {
 
 
 ///** @p prevTime param is to call clearing method after this time. */
-//void Tcanvas::correctToGuitar(TQAtype::Etype &question, int prevTime, TfingerPos& goodPos) {
+//void TtipHandler::correctToGuitar(TQAtype::Etype &question, int prevTime, TfingerPos& goodPos) {
 //  if (m_correctAnim)
 //    return;
 //  m_goodPos = goodPos;
 //  m_flyEllipse = new QGraphicsEllipseItem;
 //  m_flyEllipse->setPen(Qt::NoPen);
-//  m_flyEllipse->setBrush(QBrush(QColor(Tcore::gl()->EquestionColor.name())));
+//  m_flyEllipse->setBrush(QBrush(QColor(GLOB->EquestionColor.name())));
 //  m_scene->addItem(m_flyEllipse);
 //  if (question == TQAtype::e_asNote) {
 //      m_flyEllipse->setRect(SCORE->noteRect(1)); // 1 - answer note segment
@@ -558,7 +555,7 @@ void TtipHandler::questionTip() {
 //  m_correctAnim->setDuration(600);
 //  connect(m_correctAnim, SIGNAL(finished()), this, SLOT(correctAnimFinished()));
 //  QPointF destP = m_view->mapToScene(GUITAR->mapToParent(GUITAR->mapFromScene(GUITAR->fretToPos(goodPos))));
-//  if (!Tcore::gl()->GisRightHanded) { // fix destination position point for left-handed guitars
+//  if (!GLOB->GisRightHanded) { // fix destination position point for left-handed guitars
 //    if (goodPos.fret())
 //      destP.setX(destP.x() - GUITAR->fingerRect().width());
 //    else
@@ -570,7 +567,7 @@ void TtipHandler::questionTip() {
 //      m_correctAnim->setScaling(GUITAR->fingerRect().width() / m_flyEllipse->rect().width(), 2.0);
 //      m_correctAnim->scaling()->setEasingCurveType(QEasingCurve::OutQuint);
 //  }
-//  m_correctAnim->setColoring(QColor(Tcore::gl()->EanswerColor.name()));
+//  m_correctAnim->setColoring(QColor(GLOB->EanswerColor.name()));
 //  if (goodPos.fret() == 0) {
 //    QPointF p1(m_view->mapToScene(GUITAR->mapToParent(
 //              GUITAR->mapFromScene(GUITAR->stringLine(goodPos.str()).p1()))));
@@ -583,7 +580,7 @@ void TtipHandler::questionTip() {
 //}
 
 
-//void Tcanvas::levelStatusMessage() {
+//void TtipHandler::levelStatusMessage() {
 //#if !defined (Q_OS_ANDROID)
 //  QString message;
 //  if (m_exam->isExercise())
@@ -598,6 +595,7 @@ void TtipHandler::questionTip() {
 
 
 void TtipHandler::clearCanvas() {
+  m_confirmTipOn = false;
   emit destroyTips();
 //  clearConfirmTip();
 //  clearResultTip();
@@ -619,7 +617,7 @@ void TtipHandler::clearCanvas() {
 
 
 
-//void Tcanvas::clearCertificate() {
+//void TtipHandler::clearCertificate() {
 //  if (m_certifyTip) {
 //    m_certifyTip->deleteLater();
 //    m_certifyTip = nullptr;
@@ -627,7 +625,7 @@ void TtipHandler::clearCanvas() {
 //}
 
 
-//void Tcanvas::clearCorrection() {
+//void TtipHandler::clearCorrection() {
 //  if (m_correctAnim) {
 //    m_correctAnim->deleteLater();
 //    m_correctAnim = 0;
@@ -641,7 +639,7 @@ void TtipHandler::clearCanvas() {
 
 
 
-//void Tcanvas::clearMelodyCorrectMessage() {
+//void TtipHandler::clearMelodyCorrectMessage() {
 //  if (m_melodyCorrectMessage) {
 //    m_melodyCorrectMessage = false;
 //    levelStatusMessage();
@@ -653,16 +651,16 @@ void TtipHandler::clearCanvas() {
 ////###################              PROTECTED           ############################################
 ////#################################################################################################
 
-//void Tcanvas::correctAnimFinished() {
+//void TtipHandler::correctAnimFinished() {
 ////   clearCorrection();
 //  m_flyEllipse->hide();
 //  GUITAR->setFinger(m_goodPos);
-//  GUITAR->markAnswer(QColor(Tcore::gl()->EanswerColor.name()));
+//  GUITAR->markAnswer(QColor(GLOB->EanswerColor.name()));
 //  m_view->update();
 //}
 
 
-//bool Tcanvas::eventFilter(QObject* obj, QEvent* event) {
+//bool TtipHandler::eventFilter(QObject* obj, QEvent* event) {
 //#if defined (Q_OS_ANDROID)
 ////   if (event->type() == QEvent::KeyPress) {
 ////     auto ke = static_cast<QKeyEvent*>(event);
@@ -701,7 +699,7 @@ QPointF TtipHandler::getTipPosition(TtipHandler::EtipPos tp) {
 }
 
 
-//void Tcanvas::setTryAgainPos() {
+//void TtipHandler::setTryAgainPos() {
 //  QPointF tl(m_scene->width() * 0.6, m_scene->height() * 0.10); // top left of tip area
 //  if (m_resultTip) // place it below result tip
 //    tl.setY(m_resultTip->pos().y() + m_resultTip->realH());
@@ -709,7 +707,7 @@ QPointF TtipHandler::getTipPosition(TtipHandler::EtipPos tp) {
 //}
 
 
-//void Tcanvas::setWhatNextPos() {
+//void TtipHandler::setWhatNextPos() {
 //#if defined (Q_OS_ANDROID)
 //  qreal sc = (m_view->height() / 8.0) / m_nextTip->realH();
 //  if (sc > 1.0)
@@ -746,7 +744,7 @@ QPointF TtipHandler::getTipPosition(TtipHandler::EtipPos tp) {
 //}
 
 
-//void Tcanvas::setConfirmPos() { // right top corner
+//void TtipHandler::setConfirmPos() { // right top corner
 //#if defined (Q_OS_ANDROID)
 //  qreal sc = (m_view->height() / 8.0) / m_confirmTip->realH();
 //  if (sc > 1.0)
@@ -758,7 +756,7 @@ QPointF TtipHandler::getTipPosition(TtipHandler::EtipPos tp) {
 //}
 
 
-//void Tcanvas::createQuestionTip() {
+//void TtipHandler::createQuestionTip() {
 //  delete m_questionTip;
 //  qreal scaleFactor = 1.2;
 //#if defined (Q_OS_ANDROID) // HACK: to keep question big enough on tablet big screens
@@ -772,7 +770,7 @@ QPointF TtipHandler::getTipPosition(TtipHandler::EtipPos tp) {
 //}
 
 
-//void Tcanvas::setOutTunePos() {
+//void TtipHandler::setOutTunePos() {
 //  int startX = SOUND->pitchView()->geometry().x();
 //  if (m_outTuneTip->realW() > SOUND->pitchView()->geometry().width() / 2)
 //      m_outTuneTip->setScale(m_outTuneTip->realW() / (SOUND->pitchView()->geometry().width() / 2));
@@ -783,7 +781,7 @@ QPointF TtipHandler::getTipPosition(TtipHandler::EtipPos tp) {
 //}
 
 
-//void Tcanvas::tipStateChanged() {
+//void TtipHandler::tipStateChanged() {
 //  if (sender() == m_questionTip)
 //    m_minimizedQuestion = m_questionTip->isMinimized();
 //}
diff --git a/src/main/ttiphandler.h b/src/main/ttiphandler.h
index 0f6fc4a78..d77d0a43b 100644
--- a/src/main/ttiphandler.h
+++ b/src/main/ttiphandler.h
@@ -76,19 +76,31 @@ public:
 //     */
 //  void setStatusMessage(const QString& text, int duration = 0);
 
-  void changeExam(Texam* newExam); /**< Replaces exam pointer given in constructor to the new one. */
-
-//  void resultTip(TQAunit *answer, int time = 0); /**< show was question correct text, hides after given time */
-  void startTip(); /**< Text with help on an exam start */
-
-//    /**
-//     * Text with what to click after an answer.
-//     * @p isCorrect - was the question correct
-//     * @p toCorrection - text how to see corrected answer will be shown.
-//     */
-//  void whatNextTip(bool isCorrect, bool toCorrection = false);
-
-     /** Text with question context */
+      /**
+       * Replaces exam pointer given in constructor to the new one.
+       */
+  void changeExam(Texam* newExam);
+
+      /**
+       * show was question correct text, hides after given time
+       */
+  void resultTip(TQAunit *answer, int time = 0);
+
+      /**
+       * Text with help on an exam start
+       */
+  void startTip();
+
+   /**
+    * Text with what to click after an answer.
+    * @p isCorrect - was the question correct
+    * @p toCorrection - text how to see corrected answer will be shown.
+    */
+ void whatNextTip(bool isCorrect, bool toCorrection = false);
+
+     /**
+      * Text with question context
+      */
  void questionTip();
 //  void tryAgainTip(int time); /**< "Try again" text" */
  void confirmTip(int time = 0); /**< tip about confirm an answer appears after given time */
@@ -135,6 +147,8 @@ signals:
   void showStartTip(const QString text, const QColor& color, const QPointF& pos);
   void showQuestionTip(const QString text, const QPointF& pos);
   void destroyTips();
+  void showResultTip(const QString text, const QColor& color);
+  void destroyResultTip();
 //  void buttonClicked(const QString&); /**< This signal is emitted when user click image button (a link) on any tip.*/
 //  void certificateMagicKeys(); /**< When translator wants to see a certificate preview */
 //  void correctingFinished(); /**< Emitted when correction animation finish */
@@ -165,6 +179,7 @@ private:
   EtipPos                            m_questTipPosType; /**< Kind of question tip position */
   int                                m_iconSize; /**< Icon image size on tips calculated from actual font metrics. */
   QPointF                            m_lastTipPos;
+  bool                               m_confirmTipOn = false;
 
 private:
   QPointF getTipPosition(EtipPos tp);
diff --git a/src/nootka.qrc b/src/nootka.qrc
index ca1452273..816c6c6a4 100644
--- a/src/nootka.qrc
+++ b/src/nootka.qrc
@@ -105,6 +105,7 @@
     <file alias="exam/ResultLabel.qml">qml/exam/ResultLabel.qml</file>
     <file alias="exam/ExamTip.qml">qml/exam/ExamTip.qml</file>
     <file alias="exam/QuestionTip.qml">qml/exam/QuestionTip.qml</file>
+    <file alias="exam/ResultTip.qml">qml/exam/ResultTip.qml</file>
 
     <file alias="qtquickcontrols2.conf">qml/qtquickcontrols2.conf</file>
 <!--     <file alias="+android/qtquickcontrols2.conf">qml/+android/qtquickcontrols2.conf</file> -->
diff --git a/src/qml/exam/ExamExecutor.qml b/src/qml/exam/ExamExecutor.qml
index 26aa1f125..f9d7265ad 100644
--- a/src/qml/exam/ExamExecutor.qml
+++ b/src/qml/exam/ExamExecutor.qml
@@ -28,6 +28,10 @@ Texecutor {
       var s = Qt.createComponent("qrc:/exam/QuestionTip.qml")
       s.createObject(executor, { "text": text, "offX": pos.x, "offY": pos.y } )
     }
+    onShowResultTip: {
+      var r = Qt.createComponent("qrc:/exam/ResultTip.qml")
+      r.createObject(executor, { "text": text, "color": color } )
+    }
   }
 }
 
diff --git a/src/qml/exam/ResultTip.qml b/src/qml/exam/ResultTip.qml
new file mode 100644
index 000000000..67d79f948
--- /dev/null
+++ b/src/qml/exam/ResultTip.qml
@@ -0,0 +1,55 @@
+/** This file is part of Nootka (http://nootka.sf.net)               *
+ * Copyright (C) 2018 by Tomasz Bojczuk (seelook@gmail.com)          *
+ * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses)   */
+
+import QtQuick 2.9
+import QtGraphicalEffects 1.0
+
+
+Item {
+  id: resultTip
+
+  property alias color: txt.color
+  property alias text: txt.text
+
+  y: GLOB.useAnimations ? -2 * height : parent.height / 50
+  anchors.horizontalCenter: parent.horizontalCenter
+
+  width: txt.width; height: txt.height
+  
+  Text {
+    id: txt
+    font { pixelSize: (executor.height / 15) * (1 - 0.2 * (lineCount - 1)); family: "Sans"; bold: true }
+    visible: false
+    horizontalAlignment: Text.AlignHCenter; textFormat: Text.StyledText
+  }
+
+  DropShadow {
+    anchors.fill: txt
+    horizontalOffset: executor.height / 200
+    verticalOffset: executor.height / 200
+    radius: executor.height / 100
+    samples: 17
+    color: activPal.shadow
+    source: txt
+  }
+
+  transformOrigin: Item.Top
+
+  Connections {
+    target: executor.tipHandler
+    onDestroyResultTip: resultTip.destroy()
+  }
+
+  Component.onCompleted: {
+    if (GLOB.useAnimations)
+      anim.running = true
+  }
+
+  SequentialAnimation {
+    id: anim
+    NumberAnimation { target: resultTip; property: "y"; to: executor.height / 50; duration: 200 }
+    NumberAnimation { target: resultTip; property: "scale"; to: 2; duration: 200 }
+    NumberAnimation { target: resultTip; property: "scale"; to: 1; duration: 300 }
+  }
+}
-- 
GitLab