-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Launcher and Interactive
This is service for opening pages and dialogues.
It is available like other services through DI in cpp
and through api
in qml
.
To open a page or dialog, you need to do
launcher()->open("musescore://some/path");
or in Qml
api.launcher.open("musescore://some/path");
where musescore://some/path
is URI
Each page or dialog has a URI
, for example:
-
"musescore://home"
- Home page -
"musescore://notation"
- Notation page -
"musescore://sequencer"
- Sequencer page -
"musescore://publish"
- Publish page -
"musescore://devtools/launcher/sample"
- test dialogue for demonstration - etc
The mapping between URI
and implementation is in LaunchResolver.qml
, that is, to add a new page or dialogue that could be opened using the launcher, you need to add the appropriate mapping.
You can pass parameters to opened pages and dialogs, if they have them.
Parameter pattern: musescore://some/path?param1=value1¶mn=valuen
For example:
launcher()->open("musescore://devtools/launcher/sample?title=Test&color=#0F9D58");
The name of the parameters must correspond to the name of the properties of Qml
dialogs, or have the appropriate mapping in LaunchResolver.qml
.
Dialogues can be shown modally, for this you need to add the modal=true
parameter in URI
.
Dialogues can be showed synchronously or asynchronously; for synchronous showing, need to add the sync=true
parameter.
Dialogues can return an error code and value, they can be written to the ret
property
Qml file DevTools/Launcher/SampleDialog.qml
import QtQuick 2.7
import MuseScore.Ui 1.0
import MuseScore.UiComponents 1.0
QmlDialog {
id: root
property var color: "#444444"
width: 400
height: 400
Rectangle {
anchors.fill: parent
color: root.color
TextInputField {
id: input
property var value: ""
anchors.centerIn: parent
width: 150
height: 32
onCurrentTextEdited: input.value = newTextValue
}
Row {
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.rightMargin: 16
height: 40
width: 100
spacing: 20
FlatButton {
width: 40
text: "Ok"
onClicked: {
root.ret = {errcode: 0, value: input.value }
root.hide()
}
}
FlatButton {
width: 40
text: "Cancel"
onClicked: {
root.ret = {errcode: 3 }
root.hide()
}
}
}
}
}
Need to add to LaunchResolver.qml
r["musescore://devtools/launcher/sample"] = function(d) {
return {path: "DevTools/Launcher/SampleDialog.qml", params: d.params}
};
Opening
cpp
launcher()->open("musescore://devtools/launcher/sample?color=#0F9D58");
qml
api.launcher.open("musescore://devtools/launcher/sample?color=#0F9D58");
This is service for user interaction, ask the user something, or inform something, so that the user reacts to it.
It is available like other services through DI in cpp
, but not available in qml
.
In qml
, it is unavailable intentionally, so that qml
remains for view and logic does not leak into it.
Do not use QMessageBox or other QWidgets dialogues, use only Interactive
.
This is necessary for at least two reasons:
- To have to replace the implementation of the dialogues themselves and the style (in the future there will be only Qml dialogues)
- To be able to write unit tests, interactive can be replaced in mock.
If there is no method in interactive
to display the desired dialogue, add the method to the IInteractive
interface and implement it in Interactive
, even using standard QWidget dialogues, which can be replaced later.
You can ask the user a question using the standard buttons
IInteractive::Button btn = interactive()->question("Test", "It works?", {
IInteractive::Button::Yes,
IInteractive::Button::No });
if (btn == IInteractive::Button::Yes) {
LOGI() << "Yes!!";
} else {
LOGI() << "No!!";
}
You can ask the user a question using custom buttons
int maybeBtn = int(IInteractive::Button::CustomButton) + 1;
int btn = interactive()->question("Test", "It works?",{
IInteractive::ButtonData(maybeBtn, "Maybe"),
interactive()->buttonData(IInteractive::Button::No)
});
if (btn == maybeBtn) {
LOGI() << "Maybe!!";
} else {
LOGI() << "No!!";
}
You can show the user a message (informing, warning or error)
interactive()->message(IInteractive::Type::Critical, "Test", "This is critical text");
You may be asked to select a file to open
io::path filePath = interactive()->selectOpeningFile("Title", dir, filter);
You can do anything with the user using your dialogue
(just like when using the launcher)
RetVal<Val> rv = interactive()->require("musescore://devtools/launcher/sample?title='Test'");
if (rv.ret) {
LOGI() << "received: " << rv.val.toString();
} else if (check_ret(rv.ret, Ret::Code::Cancel)) {
LOGI() << "was cancelled";
} else {
LOGE() << "some error: " << rv.ret.code();
}
Testing
- Manual testing
- Automatic testing
Translation
Compilation
- Set up developer environment
- Install Qt and Qt Creator
- Get MuseScore's source code
- Install dependencies
- Compile on the command line
- Compile in Qt Creator
Beyond compiling
Misc. development
Architecture general
- Architecture overview
- AppShell
- Modularity
- Interact workflow
- Channels and Notifications
- Settings and Configuration
- Error handling
- Launcher and Interactive
- Keyboard Navigation
Audio
Engraving
- Style settings
- Working with style files
- Style parameter changes for 4.0
- Style parameter changes for 4.1
- Style parameter changes for 4.2
- Style parameter changes for 4.3
- Style parameter changes for 4.4
Extensions
- Extensions overview
- Manifest
- Forms
- Macros
- Api
- Legacy plugin API
Google Summer of Code
References