fix #96631 Expose TextStyleTypes to QML + test case

This commit is contained in:
Johan Temmerman 2016-02-26 18:44:58 +01:00
parent 386bb4f203
commit 0a5cc603f4
7 changed files with 499 additions and 55 deletions

View file

@ -142,6 +142,9 @@ void MScore::init()
qRegisterMetaType<Lyrics::Syllabic>("Syllabic");
qRegisterMetaType<LayoutBreak::Type>("LayoutBreakType");
qRegisterMetaType<Glissando::Type>("GlissandoType");
//classed enumerations
qRegisterMetaType<MSQE_TextStyleType::E>("TextStyleType");
#endif
// DPMM = DPI / INCH; // dots/mm
@ -352,6 +355,9 @@ QQmlEngine* MScore::qml()
qmlRegisterUncreatableType<Element>("MuseScore", 1, 0,
"Element", tr("you cannot create an element"));
//classed enumerations
qmlRegisterUncreatableType<MSQE_TextStyleType>("MuseScore", 1, 0, "TextStyleType", tr("You can't create an enum"));
//-----------virtual classes
qmlRegisterType<ChordRest>();
qmlRegisterType<SlurTie>();

View file

@ -87,6 +87,43 @@ static const int VISUAL_STRING_NONE = -100; // no ordinal for the visu
static const int STRING_NONE = -1; // no ordinal for a physical string (0 = topmost in instrument)
static const int FRET_NONE = -1; // no ordinal for a fret
//---------------------------------------------------------
// Enumeration wrapper macro allowing exposure of
// enum class to QML without manual code reproduction
//
// In addition to using this Macro, you need to do one/all of the following:
// - In mscore.cpp - QQmlEngine* MScore::qml()
// qmlRegisterUncreatableType<MSQE_name>("MuseScore", 1, 0, "name", tr("You can't create an enumeration"))
// Allows usage of name.VALUE from within a plugin as value
// - At the bottom of the file where you use this Macro
// Q_DECLARE_METATYPE(Ms::MSQE_name::E);
// Allows declaring Q_PROPERTY of the type Ms::MSQE_name::E
// Only useful if the next point is also done
// - In mscore.cpp - void MScore::init()
// qRegisterMetaType<MSQE_name::E>("name");
// Allows using Ms::MSQE_name::E as return type for the READ function
// and parameter type for the WRITE function on a Q_PROPERTY of that type
// on the condition that you also declare Q_ENUMS(Ms::MSQE_name::E)
// for that same Q_OBJECT
//
// Q_INVOKABLES can't use the QML-wrapped enum type, nor the enum class type as
// parameters. Those should be from the correct storageType and static_casts should
// be applied when necessary.
//---------------------------------------------------------
#define MS_QML_ENUM(name, storageType, ...)\
enum class name : storageType {\
__VA_ARGS__\
};\
class MSQE_##name {\
Q_GADGET\
Q_ENUMS(E)\
public:\
enum class E : storageType {\
__VA_ARGS__\
};\
};
//---------------------------------------------------------
// ArticulationType
//---------------------------------------------------------
@ -272,54 +309,53 @@ const int STAFF_GROUP_MAX = int(StaffGroup::TAB) + 1; // out of enum to avo
// Enumerate the list of build in text styles.
// Must be in sync with list in setDefaultStyle().
//---------------------------------------------------------
enum class TextStyleType : signed char {
DEFAULT = 0,
TITLE,
SUBTITLE,
COMPOSER,
POET,
LYRIC1,
LYRIC2,
FINGERING,
LH_GUITAR_FINGERING,
RH_GUITAR_FINGERING,
STRING_NUMBER,
INSTRUMENT_LONG,
INSTRUMENT_SHORT,
INSTRUMENT_EXCERPT,
DYNAMICS,
TECHNIQUE,
TEMPO,
METRONOME,
MEASURE_NUMBER,
TRANSLATOR,
TUPLET,
SYSTEM,
STAFF,
HARMONY,
REHEARSAL_MARK,
REPEAT_LEFT, // align to start of measure
REPEAT_RIGHT, // align to end of measure
REPEAT, // obsolete
VOLTA,
FRAME,
TEXTLINE,
GLISSANDO,
OTTAVA,
PEDAL,
HAIRPIN,
BENCH,
HEADER,
FOOTER,
INSTRUMENT_CHANGE,
FIGURED_BASS,
TEXT_STYLES
};
MS_QML_ENUM(TextStyleType, signed char,\
DEFAULT = 0,\
TITLE,\
SUBTITLE,\
COMPOSER,\
POET,\
LYRIC1,\
LYRIC2,\
FINGERING,\
LH_GUITAR_FINGERING,\
RH_GUITAR_FINGERING,\
\
STRING_NUMBER,\
INSTRUMENT_LONG,\
INSTRUMENT_SHORT,\
INSTRUMENT_EXCERPT,\
DYNAMICS,\
TECHNIQUE,\
TEMPO,\
METRONOME,\
MEASURE_NUMBER,\
TRANSLATOR,\
\
TUPLET,\
SYSTEM,\
STAFF,\
HARMONY,\
REHEARSAL_MARK,\
REPEAT_LEFT, /* align to start of measure */\
REPEAT_RIGHT, /* align to end of measure */\
REPEAT, /* obsolete */\
VOLTA,\
FRAME,\
\
TEXTLINE,\
GLISSANDO,\
OTTAVA,\
PEDAL,\
HAIRPIN,\
BENCH,\
HEADER,\
FOOTER,\
INSTRUMENT_CHANGE,\
FIGURED_BASS,\
\
TEXT_STYLES\
)
//---------------------------------------------------------
// BarLineType
@ -459,7 +495,5 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(Align);
Q_DECLARE_METATYPE(Ms::MScore::Direction);
Q_DECLARE_METATYPE(Ms::MScore::DirectionH);
Q_DECLARE_METATYPE(Ms::TextStyleType);
#endif

View file

@ -175,16 +175,20 @@ class TextBlock {
};
//---------------------------------------------------------
// @@ Text
// @@ MText
/// Graphic representation of a text.
//
// @P text string the raw text
// @P text string the raw text
// @P textStyleType enum (TextStyleType.DEFAULT, .TITLE, .SUBTITLE, .COMPOSER, .POET, .LYRIC1, .LYRIC2, .FINGERING, .LH_GUITAR_FINGERING, .RH_GUITAR_FINGERING, .STRING_NUMBER, .INSTRUMENT_LONG, .INSTRUMENT_SHORT, .INSTRUMENT_EXCERPT, .DYNAMICS, .TECHNIQUE, .TEMPO, .METRONOME, .MEASURE_NUMBER, .TRANSLATOR, .TUPLET, .SYSTEM, .STAFF, .HARMONY, .REHEARSAL_MARK, .REPEAT_LEFT, .REPEAT_RIGHT, .REPEAT, .VOLTA, .FRAME, .TEXTLINE, .GLISSANDO, .OTTAVA, .PEDAL, .HAIRPIN, .BENCH, .HEADER, .FOOTER, .INSTRUMENT_CHANGE, .FIGURED_BASS)
//---------------------------------------------------------
class Text : public Element {
Q_OBJECT
Q_PROPERTY(QString text READ xmlText WRITE undoSetText)
Q_PROPERTY(Ms::MSQE_TextStyleType::E textStyleType READ qmlTextStyleType WRITE qmlUndoSetTextStyleType)
Q_ENUMS(Ms::MSQE_TextStyleType::E)
QString _text;
QString oldText; // used to remember original text in edit mode
@ -244,6 +248,9 @@ class Text : public Element {
void setTextStyleType(TextStyleType);
void restyle(TextStyleType);
Ms::MSQE_TextStyleType::E qmlTextStyleType() const { return static_cast<Ms::MSQE_TextStyleType::E>(_styleIndex); }
void qmlUndoSetTextStyleType(Ms::MSQE_TextStyleType::E st) { undoChangeProperty(P_ID::TEXT_STYLE_TYPE, int(st)); }
void setPlainText(const QString&);
void setXmlText(const QString&);
QString xmlText() const { return _text; }
@ -343,4 +350,7 @@ class Text : public Element {
} // namespace Ms
Q_DECLARE_METATYPE(Ms::MSQE_TextStyleType::E);
#endif

View file

@ -0,0 +1,161 @@
<?xml version="1.0" encoding="UTF-8"?>
<museScore version="2.00">
<Score>
<LayerTag id="0" tag="default"></LayerTag>
<currentLayer>0</currentLayer>
<Division>480</Division>
<Style>
<lastSystemFillLimit>0</lastSystemFillLimit>
<page-layout>
<page-height>1683.36</page-height>
<page-width>1190.88</page-width>
<page-margins type="even">
<left-margin>56.6929</left-margin>
<right-margin>56.6929</right-margin>
<top-margin>56.6929</top-margin>
<bottom-margin>113.386</bottom-margin>
</page-margins>
<page-margins type="odd">
<left-margin>56.6929</left-margin>
<right-margin>56.6929</right-margin>
<top-margin>56.6929</top-margin>
<bottom-margin>113.386</bottom-margin>
</page-margins>
</page-layout>
<Spatium>1.76389</Spatium>
</Style>
<showInvisible>1</showInvisible>
<showUnprintable>1</showUnprintable>
<showFrames>1</showFrames>
<showMargins>0</showMargins>
<metaTag name="arranger"></metaTag>
<metaTag name="composer">Composer</metaTag>
<metaTag name="copyright"></metaTag>
<metaTag name="lyricist"></metaTag>
<metaTag name="movementNumber"></metaTag>
<metaTag name="movementTitle"></metaTag>
<metaTag name="poet"></metaTag>
<metaTag name="source"></metaTag>
<metaTag name="translator"></metaTag>
<metaTag name="workNumber"></metaTag>
<metaTag name="workTitle">Title</metaTag>
<PageList>
<Page>
<System>
</System>
<System>
</System>
</Page>
</PageList>
<Part>
<Staff id="1">
<StaffType group="pitched">
<name>stdNormal</name>
</StaffType>
</Staff>
<trackName>Piano</trackName>
<Instrument>
<longName>Piano</longName>
<shortName>Pno.</shortName>
<trackName>Piano</trackName>
<minPitchP>21</minPitchP>
<maxPitchP>108</maxPitchP>
<minPitchA>21</minPitchA>
<maxPitchA>108</maxPitchA>
<clef staff="2">F</clef>
<Articulation>
<velocity>100</velocity>
<gateTime>95</gateTime>
</Articulation>
<Articulation name="staccatissimo">
<velocity>100</velocity>
<gateTime>33</gateTime>
</Articulation>
<Articulation name="staccato">
<velocity>100</velocity>
<gateTime>50</gateTime>
</Articulation>
<Articulation name="portato">
<velocity>100</velocity>
<gateTime>67</gateTime>
</Articulation>
<Articulation name="tenuto">
<velocity>100</velocity>
<gateTime>100</gateTime>
</Articulation>
<Articulation name="marcato">
<velocity>120</velocity>
<gateTime>67</gateTime>
</Articulation>
<Articulation name="sforzato">
<velocity>120</velocity>
<gateTime>100</gateTime>
</Articulation>
<Channel>
<program value="0"/>
</Channel>
</Instrument>
</Part>
<Staff id="1">
<VBox>
<height>10</height>
<Text>
<style>Title</style>
<text>Title</text>
</Text>
<Text>
<style>Composer</style>
<text>Composer</text>
</Text>
</VBox>
<Measure number="1">
<TimeSig>
<sigN>4</sigN>
<sigD>4</sigD>
<showCourtesySig>1</showCourtesySig>
</TimeSig>
<StaffText>
<style>Figured Bass</style>
<text>System Text</text>
</StaffText>
<Rest>
<durationType>measure</durationType>
<duration z="4" n="4"/>
</Rest>
</Measure>
<Measure number="2">
<StaffText>
<text>Staff Text</text>
</StaffText>
<Rest>
<durationType>measure</durationType>
<duration z="4" n="4"/>
</Rest>
</Measure>
<Measure number="3">
<StaffText>
<style>String Number</style>
<text>Styled Technique Text</text>
</StaffText>
<Rest>
<durationType>measure</durationType>
<duration z="4" n="4"/>
</Rest>
</Measure>
<Measure number="4">
<StaffText>
<style>Rehearsal Mark</style>
<text>Rehearsal Mark</text>
</StaffText>
<Rest>
<durationType>measure</durationType>
<duration z="4" n="4"/>
</Rest>
<BarLine>
<subtype>end</subtype>
<span>1</span>
</BarLine>
</Measure>
</Staff>
</Score>
</museScore>

View file

@ -0,0 +1,161 @@
<?xml version="1.0" encoding="UTF-8"?>
<museScore version="2.00">
<Score>
<LayerTag id="0" tag="default"></LayerTag>
<currentLayer>0</currentLayer>
<Division>480</Division>
<Style>
<lastSystemFillLimit>0</lastSystemFillLimit>
<page-layout>
<page-height>1683.36</page-height>
<page-width>1190.88</page-width>
<page-margins type="even">
<left-margin>56.6929</left-margin>
<right-margin>56.6929</right-margin>
<top-margin>56.6929</top-margin>
<bottom-margin>113.386</bottom-margin>
</page-margins>
<page-margins type="odd">
<left-margin>56.6929</left-margin>
<right-margin>56.6929</right-margin>
<top-margin>56.6929</top-margin>
<bottom-margin>113.386</bottom-margin>
</page-margins>
</page-layout>
<Spatium>1.76389</Spatium>
</Style>
<showInvisible>1</showInvisible>
<showUnprintable>1</showUnprintable>
<showFrames>1</showFrames>
<showMargins>0</showMargins>
<metaTag name="arranger"></metaTag>
<metaTag name="composer">Composer</metaTag>
<metaTag name="copyright"></metaTag>
<metaTag name="lyricist"></metaTag>
<metaTag name="movementNumber"></metaTag>
<metaTag name="movementTitle"></metaTag>
<metaTag name="poet"></metaTag>
<metaTag name="source"></metaTag>
<metaTag name="translator"></metaTag>
<metaTag name="workNumber"></metaTag>
<metaTag name="workTitle">Title</metaTag>
<PageList>
<Page>
<System>
</System>
<System>
</System>
</Page>
</PageList>
<Part>
<Staff id="1">
<StaffType group="pitched">
<name>stdNormal</name>
</StaffType>
</Staff>
<trackName>Piano</trackName>
<Instrument>
<longName>Piano</longName>
<shortName>Pno.</shortName>
<trackName>Piano</trackName>
<minPitchP>21</minPitchP>
<maxPitchP>108</maxPitchP>
<minPitchA>21</minPitchA>
<maxPitchA>108</maxPitchA>
<clef staff="2">F</clef>
<Articulation>
<velocity>100</velocity>
<gateTime>95</gateTime>
</Articulation>
<Articulation name="staccatissimo">
<velocity>100</velocity>
<gateTime>33</gateTime>
</Articulation>
<Articulation name="staccato">
<velocity>100</velocity>
<gateTime>50</gateTime>
</Articulation>
<Articulation name="portato">
<velocity>100</velocity>
<gateTime>67</gateTime>
</Articulation>
<Articulation name="tenuto">
<velocity>100</velocity>
<gateTime>100</gateTime>
</Articulation>
<Articulation name="marcato">
<velocity>120</velocity>
<gateTime>67</gateTime>
</Articulation>
<Articulation name="sforzato">
<velocity>120</velocity>
<gateTime>100</gateTime>
</Articulation>
<Channel>
<program value="0"/>
</Channel>
</Instrument>
</Part>
<Staff id="1">
<VBox>
<height>10</height>
<Text>
<style>Title</style>
<text>Title</text>
</Text>
<Text>
<style>Composer</style>
<text>Composer</text>
</Text>
</VBox>
<Measure number="1">
<TimeSig>
<sigN>4</sigN>
<sigD>4</sigD>
<showCourtesySig>1</showCourtesySig>
</TimeSig>
<StaffText>
<style>System</style>
<text>System Text</text>
</StaffText>
<Rest>
<durationType>measure</durationType>
<duration z="4" n="4"/>
</Rest>
</Measure>
<Measure number="2">
<StaffText>
<text>Staff Text</text>
</StaffText>
<Rest>
<durationType>measure</durationType>
<duration z="4" n="4"/>
</Rest>
</Measure>
<Measure number="3">
<StaffText>
<style>Technique</style>
<text>Styled Technique Text</text>
</StaffText>
<Rest>
<durationType>measure</durationType>
<duration z="4" n="4"/>
</Rest>
</Measure>
<Measure number="4">
<StaffText>
<style>Rehearsal Mark</style>
<text>Rehearsal Mark</text>
</StaffText>
<Rest>
<durationType>measure</durationType>
<duration z="4" n="4"/>
</Rest>
<BarLine>
<subtype>end</subtype>
<span>1</span>
</BarLine>
</Measure>
</Staff>
</Score>
</museScore>

View file

@ -0,0 +1,25 @@
import QtQuick 2.0
import MuseScore 1.0
import MuseScore 1.0 as Ms
MuseScore {
onRun: {
var seg = curScore.firstSegment();
curScore.startCmd();
while (seg) {
for (var i = seg.annotations.length; i--; ) {
if (seg.annotations[i].type === Element.STAFF_TEXT) {
if (seg.annotations[i].textStyleType === TextStyleType.SYSTEM) {
seg.annotations[i].textStyleType = TextStyleType.FIGURED_BASS;
}
else if (seg.annotations[i].textStyleType === TextStyleType.TECHNIQUE) {
seg.annotations[i].textStyleType = TextStyleType.STRING_NUMBER;
}
}
}
seg = seg.next;
}
curScore.endCmd();
Qt.quit();
}
}

View file

@ -14,9 +14,11 @@
#include "mtest/testutils.h"
#include "libmscore/score.h"
#include "libmscore/mscore.h"
#include "libmscore/musescoreCore.h"
#include "libmscore/undo.h"
#include "mscore/qmlplugin.h"
#define DIR QString("/libmscore/plugins/")
#define DIR QString("libmscore/plugins/")
using namespace Ms;
@ -29,13 +31,37 @@ class TestPlugins : public QObject, public MTest
Q_OBJECT
QQmlEngine engine;
QQmlEngine* MsQmlEngine;
QmlPlugin* loadPlugin(QString path);
private slots:
void initTestCase();
void plugins01();
void plugins02();
void testTextStyle();
};
//---------------------------------------------------------
/// loadPlugin
/// Loads the qml plugin located at path
/// Returns pointer to the plugin or nullptr upon failure
/// Note: ensure to cleanup the returned pointer
//---------------------------------------------------------
QmlPlugin* TestPlugins::loadPlugin(QString path)
{
QQmlComponent component(MsQmlEngine);
component.loadUrl(QUrl::fromLocalFile(path));
QObject* obj = component.create();
if (obj == 0) {
foreach(QQmlError e, component.errors())
qDebug(" line %d: %s", e.line(), qPrintable(e.description()));
return nullptr;
}
return qobject_cast<QmlPlugin*>(obj);
}
//---------------------------------------------------------
// initTestCase
//---------------------------------------------------------
@ -45,6 +71,7 @@ void TestPlugins::initTestCase()
initMTest();
qmlRegisterType<MScore> ("MuseScore", 1, 0, "MScore");
qmlRegisterType<QmlPlugin> ("MuseScore", 1, 0, "MuseScore");
MsQmlEngine = Ms::MScore::qml();
}
//---------------------------------------------------------
@ -54,7 +81,7 @@ void TestPlugins::initTestCase()
void TestPlugins::plugins01()
{
QString path = root + DIR + "plugins01.qml";
QString path = root + "/" + DIR + "plugins01.qml";
QQmlComponent component(&engine,
QUrl::fromLocalFile(path));
QObject* object = component.create();
@ -80,7 +107,7 @@ void TestPlugins::plugins01()
void TestPlugins::plugins02()
{
QString path = root + DIR + "plugins02.qml";
QString path = root + "/" + DIR + "plugins02.qml";
QQmlComponent component(&engine,
QUrl::fromLocalFile(path));
QObject* object = component.create();
@ -99,6 +126,26 @@ void TestPlugins::plugins02()
delete object;
}
//---------------------------------------------------------
/// testTextStyle
/// Reading and writing of a text style through the plugin framework
//---------------------------------------------------------
void TestPlugins::testTextStyle()
{
QmlPlugin* item = loadPlugin(root + "/" + DIR + "testTextStyle.qml");
QVERIFY(item != nullptr);
Score* score = readScore(DIR + "testTextStyle.mscx");
MuseScoreCore::mscoreCore->setCurrentScore(score);
item->runPlugin();
QVERIFY(saveCompareScore(item->curScore(), "testTextStyle-test.mscx", DIR + "testTextStyle-ref.mscx"));
score->undo()->undo();
QVERIFY(saveCompareScore(item->curScore(), "testTextStyle-test2.mscx", DIR + "testTextStyle.mscx"));
delete item;
}
QTEST_MAIN(TestPlugins)
#include "tst_plugins.moc"