Separation of concerns
Try to keep content (data) separate from its presentation (how it is displayed). This enables either the content changed later without having to change the presentation, and vice versa. In web design this is achieved by using HTML files for content and CSS files for presentation.
In GUI desktop programs this is achieved by following the Model/View paradigm. Qt provides Model/View classes that make this relatively straightforward: define your model class, then use it in a view class! It is best to avoid Qt classes in
libmscore, so you may need to define a model in
mscore that simply takes data from
libmscore. This model is then provided to a view in
Use Qt Widgets (but not QWidget)
The easiest way to satisfy as many design principles as possible is to always use Qt's own widgets (QLineEdit, QPushButton, QTreeView, etc.) rather than creating your own. The look and behaviour of Qt's widgets is highly customisable and should be able to satisfy most requirements. Widgets can be added graphically to
.ui files via QtCreator's Design mode (a.k.a Qt Designer), and manipulated dynamically in the code (
If you need to customise a widget, consider subclassing one of Qt's widgets and applying your customisations to the subclass. This means the custom widget can be reused elsewhere in the code, and it is even possible to insert custom widgets in
.ui files using the promoted widgets mechanism.
Sometimes it can be useful to create a new widget that is made up of multiple Qt widgets. MuseScore's Instrument Widget (mscore/instrwidget.h, .cpp, .h) is a good example of this. The Instrument Widget is used in the Instrument Dialog (mscore/instrdialog.ui).
Creating your own widgets
If you do need to create your own widgets, try to base yours on one of the abstract widget classes (e.g. QAbstractButton, QAbstractItemView, etc.) rather than creating one from scratch. Don't subclass QWidget if you can subclass something else!
Accessibility is about making the interface usable for people with disabilities and special needs. Around 1 in 5 people have some form of disability.
It's tempting to think of accessibility as something optional that can be left until after the main design has been completed, but this is wrong and will create more work in the long term. If you get accessibility right from the beginning, it will actually make your job easier, not harder!
Tips for accessibility:
- Pick the right widgets
- Use Qt's widgets as these have accessibility support built-in
- Pick the widget that is best suited to the task at hand, and customise if necessary
- Define what widgets do
- Remember, having a label near to the widget won't help people who can't see
- Ensure all widgets have an accessible name and description
- The name and description can be similar, but they mustn't be the same
- A suitable example:
- name: "Instrument list"
- description: "List of instruments that can be added to the score"
- Define the relationship between widgets
- Install a screen reader (or enable the one that's built-in to your operating system) and try to navigate the interface using only the keyboard and with your eyes shut!
Once the interface works for users with accessibility needs, then (and only then) you can go and make it look pretty!
Screen readers on various platforms
- Windows: Narrator (built-in), NVDA (free, better than Narrator at present)
- Mac: VoiceOver (built-in)
- Linux: Orca (part of GNOME and built-in on many distributions, including Ubuntu)
- Make sure that you can tab to each item and that the tab-ordering makes sense.
- Check that the screen reader announces each widget when it receives tab focus.
- Navigate the controls (e.g. Drop-down lists, TreeView) with the arrow keys and check that the highlighted item is spoken by the screen reader.
Doing this will help users with accessibility needs, and it will also encourage you to think about how the widgets are related to each other, which often leads to a better design for all users.
Sometimes you can do everything right in your code, but find that accessibility is still sub-optimal due to a bug in the UI framework (in this case Qt) or (more rarely) a bug in the screen reader. Try to use common sense to work out where the issue lies. If it's a Qt problem the consider submitting a bug report to Qt and then move on to doing something else while waiting for it to get fixed; don't waste time writing custom hacks in MuseScore's code in an attempt to "fix" Qt problems.
Remember, Qt is supposed to give us accessibility "for free", by default for all the basic widgets (buttons, dropdowns, radiobuttons, treeviews, etc), without any effort on our part other than setting the accessible name and description. If a basic feature is not working there's a good chance it is a bug in Qt and not your code.
All designs for MuseScore should be checked against these principles.
These principles are currently mostly copies of those set out by Mozilla.
This is the most important requirement, for the the simple reason that if you get accessibility right you get most of the other requirements for free! Accessibility is also a legal requirement in many jurisdictions.
The control interface must be accessible to users with disabilities and special needs. This includes:
- People with limited mobility
- anybody who cannot use both a mouse AND a keyboard at the same time
- tip: avoid setting keyboard shortcuts that require two hands!
- People who are colour blind or struggle with visual perception
- tip: use highly contrasting colours to make it easy to tell things apart, but avoid using red and green together, and avoid using colour as the sole source of information
- People who are reliant on Assistive Technologies (screen readers, Braille terminals, etc.)
- anybody who is blind, partially sighted or otherwise unable to use the regular input devices (mouse and keyboard) or output devices (monitor and speakers) without assistance
- tip: always ensure widgets have an accessible name and description, and a well defined relationship to one another
- The elderly, and people with special cognitive needs
- tip: use sensible defaults and keep advanced settings to one side to avoid making things unnecessarily complicated
Remember, disability is extremely common! Around 1 in 5 people have some form of disability.
Taking the time to get accessibility right encourages better design in general, which benefits everyone. Even if you don't use accessibility features, you might benefit if your keyboard/mouse/speakers/monitor stops working one day and you really need to access a score!
Users should be able to discover functionality and information by visually exploring the interface; they should not be forced to recall information from memory. [Source: Nielsen]
Controls should visually express how the user should interact with them. [Source: Norman]
Controls should be placed in the correct location relative to the effect that they will have. [Source: Norman]
Controls that are more important or more commonly used should leverage visual variables such as size and contrast so that they have more dominance and weight relative to other controls.
Interfaces should be as simple as possible, both visually and interactively. Interfaces should avoid redundancy. [Source: Minimalism]
Interfaces should provide feedback about their current status. Users should never wonder what state the system is in. [Source: Nielsen]
All else being equal, software should be internally consistent with itself, and externally consistent with similar interfaces to leverage the user's existing knowledge. [Source: Nielsen]
Interfaces should be as efficient as possible, minimizing the complexity of actions and the overall time to complete a task. [Source: Nielsen]
The software should not automate tasks contrary to the user's intents.
Interfaces should not interrupt the user. Interfaces should never ask the user a question that they are not prepared to answer simply for a false sense of control. In general, software should only speak when spoken to.
Interfaces should proactively try to prevent errors from happening. [Source: Nielsen]
Actions should support undo so that users remain in control.
Users should not encounter errors because the interface is in a different state than they expected it to be.
Interfaces should proactively help users recover from both user errors and technology errors. (A preferable case is to address through ux-error-prevention so that the error does not occur). [Source: Nielsen]
Interfaces should not be organized around the underlying implementation and technology in ways that are illogical, or require the user to have access to additional information that is not found in the interface itself. [Source: Nielsen, Cooper]
Users should not be required to understand any form of implementation-level terminology. (This principle is a special case of ux-implementation-level). [Source: Nielsen]
Interfaces should not blame the user, or communicate in a way that is overly negative or dramatic.