In the process of developing a new version of QutIM, there was a need to rewrite the notification system, since the old one had many drawbacks.
Not too long ago, a topic devoted to new features that appeared in Qt appeared on Habré. In particular, it describes a new framework designed to facilitate the creation of an animated user interface. If the dear reader is not yet up to date, then I advise you first to get acquainted with this article.
A short video demonstrating the possibilities: ')
Introduction
In the review article, one worthy framework was found that I found in Qt.Labs, namely Kinetic . The authors promise us the following:
Animation framework - the ability to create both simple and complex types of animation for any type of widget. Providing finished animation, the ability to add and create custom.
The declarative creation of an interface is the task of an interface by describing its properties, and not by manipulating ready-made templates.
Advanced graphics capabilities - add shadows, transparency, filters, and so on.
It looks delicious, right? Therefore, I, armed with patience and readiness for the unknown, wrote a small example. I note that it took much less time than expected. Movements of notifications turned out smooth. They themselves are always lined up so as not to overlap the neighboring ones, and in the case when the text does not fit, the window will automatically be scaled. What is needed in order to create a library that can display these notifications?
KineticNotifications - through this class and notifications will be sent. The class is responsible for displaying and animating notifications.
NotificationWidget - pamo popup notification, is a QTextBrowser with a frame removed and an alpha channel added.
Notification Manager is a singleton that stores pointers to all running notifications, controls their placement, and also provides settings.
Program code
In order to trigger a notification, a couple of lines are enough:
Each notification is assigned its own identifier, which must be unique. This allows you to get by the identifier a pointer to an already existing notification, in order, for example, to add a line to it.
notify -> appendMessage ( QString :: fromUtf8 ( "Add a string of text" ) ) ;
}
It is important to remember that if there is no notification with the requested id, the function will return 0.
We now turn to the most important thing: the description of the State machine. First you need to create all the states of the machine. In total there will be three:
show_state - the notification is shown on the screen
hide_state - notification is hidden
final_state - this position stops the state machine
show_state -> addTransition ( this , SIGNAL ( updated ( ) ) , show_state ) ; // a little trick
The last line allows you to do without the additional state of the machine if you need to change the position on the screen of the previously drawn notification. After that, you need to set the starting position for the notification (on the right-hand side of the screen) and the position that the notification will take, going to the show_state state. The position and size of the widget can be set using the setGeometry method, whose argument is a QRect, which is nothing more than a rectangle that has the coordinate of the upper left point, as well as its height and height. To find out at which point on the screen you need to create a notification and where to move it then we need to know the position of the previous widget or, in the absence of such a lower right corner:
And as a result, we get the angle of the monitor on which the mouse pointer!
The starting point has been obtained, now you can set the text, change the height of the widget to the optimum, so that it can fit all the displayed text and images.
int height = this -> document ( ) -> size ( ) . height ( ) ;
return QSize ( width , height ) ;
Be sure to ask what stage follows what and what condition is necessary to move the machine from one stage to another.
if ( timeOut > 0 ) {
startTimer ( timeOut ) ;
show_state -> addTransition ( this , SIGNAL ( timeoutReached ( ) ) , hide_state ) ;
}
machine. addState ( show_state ) ;
machine. addState ( hide_state ) ;
machine. addState ( final_state ) ;
machine. setInitialState ( show_state ) ;
But the position and size of notifications periodically have to be changed, for example, if the bottom widget disappears, then all other notifications should be moved down so as not to create empty space. The same applies to adding text: sooner or later you will have to resize the widget and, accordingly, move all the others so that none of them overlaps the other. In addition, it is very important to know the final position of the notification, since it is necessary for correct recalculation of the position of the entire chain. Otherwise, the instantaneous position and size of the notification in the process of its movement can be obtained, as a result of which the widgets will assume the wrong position. To update, it is enough to call a function in the singleton that will recalculate the positions of the widgets from the bottom right edge of the screen.
Thus, it is sufficient for any event that may lead to a change in the position or size of the widget to trigger the update function. These events include the removal of the widget and the addition of additional lines to it. In general, it turned out very functional and rather succinctly.
Conclusion
For those who are interested in the implementation of the notification widget, and who are interested in learning more about the work of the library, and also use it, link to the source code, the LGPL license. This program was tested on Qt4.6tp1, kinetic brunch 4.5 branches and should work with QAnimationFramework from Qt Solutions. Enjoy using
NB Published at the request of one good person from the QutIM development team, who does not have an account on Habré, but would like to participate in the community life.Here is his mail: sauron@citadelspb.com