Skip to content

Thursday, 13 April 2023

Today, we bring you a quick report on the Maui Project’s progress after our previous 2.2.2 release; here you will find some detailed information on the new features, bug fixes, and improvements that have been made to the Maui set of apps and frameworks.

To follow the Maui Project’s development or say hi, you can join us on Telegram: https://t.me/mauiproject.

We are present on Twitter and Mastodon:

What’s new?

Besides the common bug fixes, some of the highlights include a refactor and cleanup of some of the MauiKit Frameworks, and new and improved Maui Apps, with support for true black color style, improved startup times, faster GPS scanning, more options in the settings app, and a brand new QPA Theme plugin for Cask to make Qt apps look and feel better under Maui Shell, among many other tweaks and refinements.

On the road to Maui 3. Focused on the framework and the apps. working on the new apps to bring them up paired with the most stable ones.

Porting to Qt6

MauiMan and MauiKit will be the two first projects to be ported, the progress so far has not been very active but now that all Plasma and KDE Libraries are now Qt6 in master, work on this area will be resumed.

https://invent.kde.org/maui/mauikit/-/issues/35

Maui Shell

For this new development cycle, the focus is on the MauiKit Frameworks and Maui Apps, however, a few fixes will land in the stack of the Maui Shell. Here are a few of the highlights so far.

Cask

  • Fix bugs on dragging around CSD surfaces.
  • Now uses the new MauiMan InputDevices keymap properties.
  • Now uses the new QPA Theme and set the right env var to make use of it.
  • Other Qt applications now look better with the new Maui QPA Theme.
  • Tweaked the padding of the Chrome title bars.

Maui Settings

  • The Theme module view has been refactored and split into subpages for better readability.
  • Added a new sub-page to support picking custom color schemes.
  • New QPA Theme plugin.
  • Added a new Fonts subpage in Theme.
  • Added entry to pick a custom wallpaper source directory in the Background module view.
  • Organize the sidebar modules by categories.
  • Can now filter the sidebar categories with keywords.
  • Display an error message when a module could not be loaded correctly.
  • Added the new InputDevices modules view with initial support for keyboard keymap options.
  • Tweaked the About module view.
  • Added a filter field for the Icons subpage.

 

 

MauiMan

  • The Theme module gained new props for the fonts: DefaultFont, SmallFont, and MonospaceFont.
  • Initial work has been started for the InputDevices module, starting with the keyboard keymaps options.

MauiKit Frameworks

MauiKit Core components have seen many fixes and improvements, from consistency in the UI and UX department, fixes in binding loops bugs, implementation cleanups, and new features or existing ones being exposed.

Overall you will notice an even more cohesive usage of padding, margins, and spacing in elements and content views. More work towards making it perfectly suitable for desktop and mobile use.

Gained support for two new styles: Inverted and TrueBlack, among many other fixes listed down below:

 

 

Core

  • The FlexLisItem control is now based on a Grid allowing finer control over the layout. The property columns is exposed to determine the initial layout, and child items can now be positioned using the attached properties from Layout. By default, the FlexListItem has 2 columns in wide mode and goes to 1 column on constrained widths, but if you need to position more items you can increment the number of columns.
  • Fixed the Android Gradle build files referencing the manifest.
  • The Style font properties were refined and no longer use bad point sizes. Now the font properties rely on the wide system preferences for the default font, small font, and monospaced font, this is done via the QPA Theme plugin. As a result of the refactoring now all Maui Apps will correctly redraw the fonts when they’re changed from the system settings.
  • Correct the size and style of the Switch control for consistency.
  • React to icon theme changes from the system settings.
  • Use the QPA style hints and expose some of them in the Style object, such as whether to show icons in menus: Maui.Style.menusHaveIcons.
  • Fixed the ComboBox popup implicit height.
  • New controls added: FontPicker and FontPickerDialog, which allow picking font family, best-fitted sizes, style, and filters for only monospaced fonts; and display a preview.
  • Now the rendering of the buttons and menu items contents no longer uses the QQC2 hidden implementation and instead uses the new IconLabel control.
  • Fixes to the color styles: dark, light, and custom. The custom style uses the Plasma custom color scheme definitions from files.
  • Fixed the masking area of the image in the IconItem control.
  • Removed the BasicToolButton, now that all buttons use the new Iconlabel implementation.
  • Chip control now is checkable and no longer displays tooltips unless needed.
  • The TabView control has been refactored and now using it is much easy, besides adding new tabs dynamically via the functions, tabs can now also be declared as children and it will work. Also, there is no longer the need to set the child tab sizes, the TabView will resize the children to fit. In the refactoring process, there were also fixes for the DnD reordering of tabs and focusing. The TabViewInfo attached properties gained new props: TabViewInfo.tabIcon and TabViewInfo.tabColor.
  • The MauiKit-based apps now have a new true black color scheme alternative, that can be activated from the app itself using the Maui.Style.trueBlack option, or globally from MauiMan.
  • Maintain a uniform height for the ToolActions control.
  • A few new CSD styles have been added, and the Dynamic one, which relied on applet-window-buttons, has been removed.
  • New ToastArea for in-app notifications, which allows having multiple notifications stacked. This is better than the previous implementation based on a Dialog. The ToastArea can be easily dismissed and individual notifications can be swiped off via touch or closed via mouse clicks.
  • Added notification sounds taken from the free Material resources.
  • Fixes the FloatingButton control sizing.

FileBrowsing

  • Fixes to the Tagging DB thread-safe implementation.
  • Tweak the TagDelegates and TagBar controls.
  • Fixed the FileBrowser focus issues.
  • Nicer FileBrowser dialogs.

ImageTools

  • Make Tesseract and Leptonica required dependencies.
  • Refactored the messy pointers implementation of the Geolocation classes and make it thread-safe.

Terminal – New!

  • Fixed the issue with double pasting text
  • Updated the custom adaptive color scheme, from picking it from a file to being declared in QML.
  • The Adaptive color scheme now works better, by checking the brightness and other factors.
  • The property hasActiveProcess now has a notify signal.
  • Added new property: readOnly for cases when the terminal should not receive any user inputs, but still can use methods such as sendText or sendKeyPress, etc…
  • Support highlighting search results in the history.
  • Tweaked the search bar, with a dedicated button to jump through finds and more options.
  • Added a virtual keyboard toggle floating button for mobile devices.

Maui Apps

Although in this new release cycle the focus was on Maui Shell projects, many of the Maui Apps received some love: new features, improvements, and updates.

Index

  • Browser items focus issues have been fixed.
  • A bug from the selection bar causing a failure to perform actions has been fixed.
  • The PathBar arrow delegates are now better renderer antialias.
  • Updated to use the new MauiKit ToastArea notifications.

Pix

  • New layout with a global sidebar for navigation.
  • Faster lookup of the GPS locations using concurrency.
  • The new sidebar now lists tags, sources, and known categories.
  • Split the viewer from the collection browser for faster startup time when only opening an image in the viewer.
  • Escape keyboard shortcuts to go back from the browser.
  • Fixes the navigation patterns, from the browser to the viewer.

Nota

  • Fix crashing issues with the places sidebar under Android when external SD cards are present.
  • Tweak the settings dialog entries order.
  • Check the existence of a directory before opening the file dialog in such path.
  • Escape keyboard shortcuts for exiting the recent documents view.
  • Updated to the latest MauiKit changes.
  • Collection views now display location tags if any are found.

Station

  • Support for finding text and highlighting the results.
  • Display warnings when trying to close a view with a running process.
  • Display warning when trying to close the app but a process in some views is still running.
  • Extend the translucency effect to the tab bar.
  • Use the new MauiKit FontPicker control to pick a new font.
  • Use the new MauiMan style property MonospacedFont as a default font.
  • Fixes issues when focusing the terminal and opening the virtual keyboard on mobile devices.
  • Make MauiKit-Terminal a required package.
  • Added a placeholder message when there are no tabs opened.
  • Added alerts when a process has been finished making use of the new Mauikit ToastArea notifications.
  • Fixes the virtual keyboard not being opened when the terminal gets focused.
  • Refactored the translucency entry to use a switch instead of a slider.

 

Paleta

  • Updated to latest MauiKit changes.
  • Notify using the new ToastArea.
  • Display colors WCAG contrast ratio.

Bonsai

  • Added support for more action commands, such as pull, stash, and status.
  • Refactor the Project object to allow quick cloning of new projects.
  • Now uses libkommit library instead of previous libgit2-based wrappers.

Fiery

  • Now uses sidebar navigation for browsing the collection sources.

Arca

  • Initial support for creating new archives from within the app.

And the rest of the fixes to the rest of the applications…

 

That’s it for now. Until the next blog post, that will be a bit closer to the 3.0.0 stable release.

 

To follow the Maui Project’s development or say hi, you can join us on Telegram: https://t.me/mauiproject.

We are present on Twitter and Mastodon:

New release schedule

The post Maui Report 22 appeared first on MauiKit — #UIFramework.

My second release of the day: Kirigami Addons 0.8.0. This release contains a few new components.

AbstractMaximizeComponent

This is part of the org.kde.kirigamiaddons.labs.components module and is a popup that covers the entire window to show some items. This is already used in NeoChat and Tokodon to magnify image and videos.

Thanks James Graham for developing the initial version and upstreaming it to Kirigami-addons.

Maximized image in NeoChat
Maximized image in NeoChat

Convergent SpinBox

Another new component is the convergent SpinBox from the org.kde.kirigamiaddons.labs.mobileform module.

This is just a normal spinbox on desktop.

Spinbox on desktop with small touch targets
Spinbox on desktop with small touch targets

But on Plasma Mobile/Android the touch target becomes bigger.

Spinbox on desktop with larger touch targets
Spinbox on desktop with larger touch targets

Others

Aside from this two components this release contains some small bugfixes and other minor API improvememts.

Get Involved

If you are interested in helping, don’t hesitate to reach out in the Plasma Mobile matrix channel (#plasmamobile:kde.org) and I will be happy to guide you.

And in case, you missed it, as a member of KDE’s fundraising working group, I need to remind you that KDE e.V., the non-profit behind the KDE community accepts donations.

Packager section

You can find the package on download.kde.org and it has been signed with my GPG key.

I’m happy to announce the initial release of Arianna. Arianna is a small ePub reader application I started with Niccolo a few months ago. Like most of my open source applications, it is built on top of Qt and Kirigami.

Arianna is both an ePub viewer and a library management app. Internally, Arianna uses Baloo to find your existing ePub files in your device and categorize them.

Library view
Library view

The library view will keep track of your reading progress and find new books as soon as you download them.

If your book library is particularly big, you can either use the internal search functionality, or look through the various categories and find books grouped by genre, publisher or author.

Library search popup showing a few search results
Library search popup showing a few search results

Library grouped by authors
Library grouped by authors

The actual reader is quite basic as its only function is to show the content of the book. That said, it does have features like a progress bar to keep track of your reading progress and also lets you navigate within the book.

It is also fully navigable with the keyboard.

Ebook reader showing the book content
Ebook reader showing the book content

Another feature allows you to search within a book for a specific word.

Ebook reader showing the book content
Ebook reader showing the book content

Get it

Arianna will soon be available in Flathub (once the submittion is accepted). Please also ask your distribution to package Arianna.

Credits

This application would have not been possible without the previous work carried out by Foliate, from whom I copied and adapted the epub.js integration, and Peruse from whom I copied and adapted the library management code. Finally I would like to thank Šimon Rataj who made numerous contribution and fixed multiple bugs.

Arianna is also translated in multiple languages, thanks to some wonderful translators. Here is the alphabethically sorted list: Basque, British English, Catalan, Czech, Dutsch, Finish, French, German, Georgian, Hungarian, Interlingua, Mandarin, Portuguese, Slovak, Spanish, Turkish, Ukrainian and Valencian.

Get Involved

If you are interested in helping, don’t hesitate to reach out in the Arianna matrix channel (#arianna:kde.org) and I will be happy to guide you.

I also regularly post about my progress on Arianna (and other KDE apps) on my Mastodon account, so don’t hesitate to follow me there ;)

And in case, you missed it, as a member of KDE’s fundraising working group, I need to remind you that KDE e.V., the non-profit behind the KDE community accepts donations.

Packager section

You can find the package on download.kde.org and it has been signed with my GPG key.

Tuesday, 11 April 2023

After a very long pause, I am happy to announce the release of Nanonote 1.4.0.

Nanonote is a minimalist note-taking application. It consists of a text area, a context menu and... that's about it!

It's handy to jot down short term notes, as a temporary place to collect copy'n'paste blocks, to draft a long response for an instant messaging app without having to fear pressing Enter too soon or any other use you can come up with!

TODO lists

Nanonote can also be used to write TODO lists. This is even better now in 1.4.0 thanks to the new task feature from Daniel Laidig, which lets you quickly create and toggle checkable tasks with Ctrl+Enter.

tasks.webm

Markdown-like headings

Nanonote is not a Markdown editor, but I often found myself separating notes with Markdown-like headings. Issue #43, convinced me to add some light styling for headings:

Markdown-like headings

More changes

For a complete list of changes, have a look at the CHANGELOG.

Get it!

You can find .deb, .rpm, macOS dmg and Windows installers on the release page.

For Linux users, Nanonote is now also available on Flathub.

KDE Connect was designed 10 years ago (!) with Android smartphones as one of our first supported platforms. Because of that, when designing the KDE Connect protocol we had to work around many technical limitations that Android had back in its infancy.

This year I will be working on a project named “KDE Connect discovery and transport protocol improvements” that received a grant from the NLnet foundation as part of the NGI Assure fund. This grant will allow me to work full time in KDE Connect, with the goal of updating the protocol and apps to modern standards.

Below are the 3 main areas that will improve thanks to this and become KDE Connect 2.0 (even though some changes will show up sooner, because we release early, release often).

Reliability

The strength of KDE Connect (compared to some of the non-free alternatives that popped up in these last 10 years) is that KDE Connect only uses your local network for communication and doesn’t need intermediary servers in “the cloud“. This adds a challenge: devices running KDE Connect have to discover each other in the network before they can talk to each other.

Discovery is possible in the current protocol using UDP broadcasts, but the state of the art nowadays is to use multicast DNS (mDNS) instead, which is more reliable and less often blocked by the network configuration. We wanted (and tried) to adopt mDNS for a while, but it was a a bigger endeavour than what we could tackle.

By focussing full time on this, my goal is to implement an mDNS backend for KDE Connect on all supported platforms (Linux, Windows, MacOS, Android and iOS) before fall this year. Wish me luck!

Security

Before Android 5, only TLSv1 and a limited set of cipher suites could be used. We always try to stay compatible with old devices and to fight the programmed obsolescence that plagues modern technology, but that meant keeping the KDE Connect protocol compatible with insecure encryption protocols.

Starting with KDE Connect v1.22 for Android, we now require Android 5 or later so we can drop compatibility with insecure encryption in all the KDE Connect implementations (and not only Android). In addition to that, we are reviewing and updating the dependencies we bundle as part of the app to make sure we have the latest security patches.

Later this year, and also thanks to NLnet, we will get a security audit by Radically Open Security. This will be the second time KDE Connect is audited, after the openSUSE security team did so in 2020.

Accessibility

We recently adopted Material 3 in the Android app (thanks Dmitry Yudin for doing most of the work!) and KDE as a whole is getting ready to migrate our desktop apps to Qt6. These times are a perfect opportunity to review the accessibility of our user interfaces, and for that NLnet is helping us get an accessibility audit by the HAN University also later this year.

All in all, exciting times for the KDE Connect project! Stay tuned for future updates :)

Tuesday, 11 October 2022

This year, I had the amazing opportunity to attend KDE Akademy in person for the first time! The host city was Barcelona. It is my second time visiting the city but it was my first time to attend KDE Akademy. Actually it was my first KDE event.

For KDE friends who don't know me, I mainly contribute to openSUSE, GNOME, Nextcloud, ownCloud and GNU Health. I have fewer contributions to Fedora, Ubuntu and ONLYOFFICE and a few here and there to FOSS projects.

Question. Why did you attend KDE Akademy? Two were the reasons. The first and main reason was to see the organization of the conference from the inside, since my University will host the next KDE Akademy. The second reason was to "introduce" myself to the KDE community, since I contribute to other projects. Actually, I know a person from the KDE board but community is not only one person.

The only familiar person I could meet was openSUSE's community manager. Unfortunately he couldn't attend, so he asked me to represent openSUSE. The duties were to have a booth and present something openSUSE related for 3 minutes. I had an idea to propose my friend George to do his first presentation to an open source conference and start his open source journey. He was very excited and he did it.

Day 0

There was a welcome event on Friday for us, where attendees got to know each other. Unfortunately, my flight was delayed and I arrived too late to attend the event. So I stayed at the hotel and tried to rest for my first Akademy day. I felt like going to school.

Day 1

The first thing we had to do was set up our booth. Well, the only promo material we had was stickers. I think all geeks like stickers so it was the best gift for everyone. I love stickers, not only from openSUSE but from other projects as well.
Stathis at openSUSE booth
During setting up the booth, I met the rest of the guys from the sponsors like Ubuntu, Fedora, Qt and Slim Book.

I attended quite a few interesting talks:Food at the coference wasn't the best for my taste. Maybe it's me. But the most interesting part of the conference was the fact that I had the chance to meet realy important people, developers that changed my point of view on softare developement.

You can see the first day, Room 1 here:

Day 2

After having fun the first day, I was excited for the second day. The first reason was that George and I (actually only George) will have the sponsor talk and the second reason was that the fact that the organizers would announce the place of next year's Akademy. Of cource that place is Thessaloniki and my University.

I attended quite a few interesting talks:You can see the second day, Room 1 here:
Unfortunately I didn't have any team to join the next BoFs days. I had a small hope that we could setup the working environment for the next Akademy but that didn't happen.

We didn't join the trip to the mountain. We went to see the city. It was my second time and I skipped some sites.

I really loved my first KDE Akademy. I would like to thank KDE ev that sponsored my trip to attend the Akademy.

I have a lot of stuff to work here with the organizing committee.
We are working to host you all next year.

Wednesday, 17 August 2022

KDE Akademy 2022
Happy traveller is back. Happy open source conference guy is ready for another trip. This time my destination is KDE Akademy and Barcelona. It's my first time attending to Akademy and I am soooooo excited. It's also my second time in Barcelona. Thanks to my highschool, I have been to Barcelona participating in the Erasmus + mobility program (article in Greek). According to the legent, maybe me kissing weird things in Girona worked just fine (click to see the picture).

You don't need to be a "KDE expert" to join, I know I am not. If you're interested in KDE you should really attend if you can (in person if possible), and not only the weekend of talks, but the whole week! And you should register today!

For those of you who know me, I used to attend conferences alone. This time we are 3 people from my university, the University of Macedonia. We have a newly formed Open Source Team and I would like to bring more people with me, to join global communities.

I will keep this short. More to come soon.

I would like to thank KDE and the community for the opportunity to join such a big conference. I am so happy that I will meet you in person after those 2 years of COVID-19 era.

Thursday, 25 August 2016

The function evolution…

I would like to show the evolution of one function in rolisteam code.
This function is called when the user (Game Master) closes a map or image.

The function must close the map or image and send a network order to each player to close the image or plan.

At the beginning, the function looked like that.
Some code line and comments were written in French. No coding rules were respected.
Low-level code for networking. The function was very long.

[pastacode lang=”cpp” message=”” highlight=”” provider=”manual” manual=”%20%2F%2F%20On%20recupere%20la%20fenetre%20active%20(qui%20est%20forcement%20de%20type%20CarteFenetre%20ou%20Image%2C%20sans%20quoi%20l’action%0A%20%20%20%20%20%20%20%20%2F%2F%20ne%20serait%20pas%20dispo%20dans%20le%20menu%20Fichier)%0A%20%20%20%20%20%20%20%20QWidget%20*active%20%3D%20workspace-%3EactiveWindow()%3B%0A%0A%20%20%20%20%20%20%20%20%2F%2F%20Ne%20devrait%20jamais%20arriver%0A%20%20%20%20%20%20%20%20if%20(!active)%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20qWarning(%22Close%20map%20action%20called%20when%20no%20widget%20is%20active%20in%20the%20workspace%20(fermerPlanOuImage%20-%20MainWindow.h)%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%3B%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20%2F%2F%20On%20verifie%20pour%20le%20principe%20qu’il%20s’agit%20bien%20d’une%20CarteFenetre%20ou%20d’une%20Image%0A%20%20%20%20%20%20%20%20if%20(active-%3EobjectName()%20!%3D%20%22CarteFenetre%22%20%26%26%20active-%3EobjectName()%20!%3D%20%22Image%22)%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20qWarning(%22not%20expected%20type%20of%20windows%20(fermerPlanOuImage%20-%20MainWindow.h)%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%3B%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20%2F%2F%20Creation%20de%20la%20boite%20d’alerte%0A%20%20%20%20%20%20%20%20QMessageBox%20msgBox(this)%3B%0A%20%20%20%20%20%20%20%20msgBox.addButton(QMessageBox%3A%3AYes)%3B%0A%20%20%20%20%20%20%20%20msgBox.addButton(QMessageBox%3A%3ACancel)%3B%0A%20%20%20%20%20%20%20%20msgBox.setIcon(QMessageBox%3A%3AInformation)%3B%0A%20%20%20%20%20%20%20%20msgBox.move(QPoint(width()%2F2%2C%20height()%2F2)%20%2B%20QPoint(-100%2C%20-50))%3B%0A%20%20%20%20%20%20%20%20%2F%2F%20On%20supprime%20l’icone%20de%20la%20barre%20de%20titre%0A%20%20%20%20%20%20%20%20Qt%3A%3AWindowFlags%20flags%20%3D%20msgBox.windowFlags()%3B%0A%20%20%20%20%20%20%20%20msgBox.setWindowFlags(flags%20%5E%20Qt%3A%3AWindowSystemMenuHint)%3B%0A%20%20%20%20%20%20%20%20%2F%2F%20M.a.j%20du%20titre%20et%20du%20message%0A%20%20%20%20%20%20%20%20if%20(active-%3EobjectName()%20%3D%3D%20%22CarteFenetre%22)%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20msgBox.setWindowTitle(tr(%22Close%20Map%22))%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20msgBox.setText(tr(%22Do%20you%20want%20to%20close%20this%20map%3F%5CnIt%20will%20be%20closed%20for%20everybody%22))%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20else%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20msgBox.setWindowTitle(tr(%22Close%20Picture%22))%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20msgBox.setText(tr(%22Do%20you%20want%20to%20close%20this%20picture%3F%5CnIt%20will%20be%20closed%20for%20everybody%22))%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20msgBox.exec()%3B%0A%0A%20%20%20%20%20%20%20%20%2F%2F%20Si%20l’utilisateur%20n’a%20pas%20clique%20sur%20%22Fermer%22%2C%20on%20quitte%0A%20%20%20%20%20%20%20%20if%20(msgBox.result()%20!%3D%20QMessageBox%3A%3AYesRole)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%3B%0A%0A%20%20%20%20%20%20%20%20%2F%2F%20Emission%20de%20la%20demande%20de%20fermeture%20de%20la%20carte%0A%20%20%20%20%20%20%20%20if%20(active-%3EobjectName()%20%3D%3D%20%22CarteFenetre%22)%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20Recuperation%20de%20l’identifiant%20de%20la%20carte%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20QString%20idCarte%20%3D%20((CarteFenetre%20*)active)-%3Ecarte()-%3EidentifiantCarte()%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20Taille%20des%20donnees%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20quint32%20tailleCorps%20%3D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20Taille%20de%20l’identifiant%20de%20la%20carte%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20sizeof(quint8)%20%2B%20idCarte.size()*sizeof(QChar)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20Buffer%20d’emission%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20char%20*donnees%20%3D%20new%20char%5BtailleCorps%20%2B%20sizeof(enteteMessage)%5D%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20Creation%20de%20l’entete%20du%20message%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20enteteMessage%20*uneEntete%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20uneEntete%20%3D%20(enteteMessage%20*)%20donnees%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20uneEntete-%3Ecategorie%20%3D%20plan%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20uneEntete-%3Eaction%20%3D%20fermerPlan%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20uneEntete-%3EtailleDonnees%20%3D%20tailleCorps%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20Creation%20du%20corps%20du%20message%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20int%20p%20%3D%20sizeof(enteteMessage)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20Ajout%20de%20l’identifiant%20de%20la%20carte%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20quint8%20tailleIdCarte%20%3D%20idCarte.size()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20memcpy(%26(donnees%5Bp%5D)%2C%20%26tailleIdCarte%2C%20sizeof(quint8))%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20p%2B%3Dsizeof(quint8)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20memcpy(%26(donnees%5Bp%5D)%2C%20idCarte.data()%2C%20tailleIdCarte*sizeof(QChar))%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20p%2B%3DtailleIdCarte*sizeof(QChar)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20Emission%20de%20la%20demande%20de%20fermeture%20de%20la%20carte%20au%20serveur%20ou%20a%20l’ensemble%20des%20clients%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20emettre(donnees%2C%20tailleCorps%20%2B%20sizeof(enteteMessage))%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20Liberation%20du%20buffer%20d’emission%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20delete%5B%5D%20donnees%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20Suppression%20de%20la%20CarteFenetre%20et%20de%20l’action%20associee%20sur%20l’ordinateur%20local%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20((CarteFenetre%20*)active)-%3E~CarteFenetre()%3B%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20%2F%2F%20Emission%20de%20la%20demande%20de%20fermeture%20de%20l’image%0A%20%20%20%20%20%20%20%20else%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20Recuperation%20de%20l’identifiant%20de%20la%20carte%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20QString%20idImage%20%3D%20((Image%20*)active)-%3EidentifiantImage()%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20Taille%20des%20donnees%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20quint32%20tailleCorps%20%3D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20Taille%20de%20l’identifiant%20de%20la%20carte%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20sizeof(quint8)%20%2B%20idImage.size()*sizeof(QChar)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20Buffer%20d’emission%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20char%20*donnees%20%3D%20new%20char%5BtailleCorps%20%2B%20sizeof(enteteMessage)%5D%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20Creation%20de%20l’entete%20du%20message%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20enteteMessage%20*uneEntete%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20uneEntete%20%3D%20(enteteMessage%20*)%20donnees%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20uneEntete-%3Ecategorie%20%3D%20image%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20uneEntete-%3Eaction%20%3D%20fermerImage%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20uneEntete-%3EtailleDonnees%20%3D%20tailleCorps%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20Creation%20du%20corps%20du%20message%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20int%20p%20%3D%20sizeof(enteteMessage)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20Ajout%20de%20l’identifiant%20de%20la%20carte%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20quint8%20tailleIdImage%20%3D%20idImage.size()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20memcpy(%26(donnees%5Bp%5D)%2C%20%26tailleIdImage%2C%20sizeof(quint8))%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20p%2B%3Dsizeof(quint8)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20memcpy(%26(donnees%5Bp%5D)%2C%20idImage.data()%2C%20tailleIdImage*sizeof(QChar))%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20p%2B%3DtailleIdImage*sizeof(QChar)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20Emission%20de%20la%20demande%20de%20fermeture%20de%20l’image%20au%20serveur%20ou%20a%20l’ensemble%20des%20clients%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20emettre(donnees%2C%20tailleCorps%20%2B%20sizeof(enteteMessage))%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20Liberation%20du%20buffer%20d’emission%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20delete%5B%5D%20donnees%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20Suppression%20de%20l’Image%20et%20de%20l’action%20associee%20sur%20l’ordinateur%20local%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20((Image%20*)active)-%3E~Image()%3B%0A%20%20%20%20%20%20%20%20%7D”/]

A big step forward, the networking code has been reworked.
So the readability is improved. It is also possible to see the beginning of polymorphism. MediaContener is used but not everywhere.

[pastacode lang=”cpp” message=”Version Intermédiaire” highlight=”” provider=”manual” manual=”QMdiSubWindow*%20subactive%20%3D%20m_mdiArea-%3EcurrentSubWindow()%3B%0AQWidget*%20active%20%3D%20subactive%3B%0AMapFrame*%20bipMapWindow%20%3D%20NULL%3B%0A%0Aif%20(NULL!%3Dactive)%0A%7B%0A%0A%20%20%20%20QAction*%20action%3DNULL%3B%0A%0A%20%20%20%20Image*%20%20imageFenetre%20%3D%20dynamic_cast(active)%3B%0A%0A%20%20%20%20QString%20mapImageId%3B%0A%20%20%20%20QString%20mapImageTitle%3B%0A%20%20%20%20mapImageTitle%20%3D%20active-%3EwindowTitle()%3B%0A%20%20%20%20bool%20image%3Dfalse%3B%0A%20%20%20%20%2F%2Fit%20is%20image%0A%20%20%20%20if(NULL!%3DimageFenetre)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20m_pictureList.removeOne(imageFenetre)%3B%0A%0A%20%20%20%20%20%20%20%20mapImageId%20%3D%20imageFenetre-%3EgetMediaId()%3B%0A%20%20%20%20%20%20%20%20image%20%3D%20true%3B%0A%20%20%20%20%20%20%20%20action%20%3D%20imageFenetre-%3EgetAction()%3B%0A%20%20%20%20%7D%0A%20%20%20%20else%2F%2Fit%20is%20a%20map%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20bipMapWindow%3D%20dynamic_cast(active)%3B%0A%20%20%20%20%20%20%20%20if(NULL!%3DbipMapWindow)%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20mapImageId%20%3D%20bipMapWindow-%3EgetMediaId()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20action%20%3D%20bipMapWindow-%3EgetAction()%3B%0A%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20else%2F%2F%20it%20is%20undefined%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20return%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%0A%20%20%20%20QMessageBox%20msgBox(this)%3B%0A%20%20%20%20msgBox.setStandardButtons(QMessageBox%3A%3AYes%20%7C%20QMessageBox%3A%3ACancel%20)%3B%0A%20%20%20%20msgBox.setDefaultButton(QMessageBox%3A%3ACancel)%3B%0A%20%20%20%20msgBox.setIcon(QMessageBox%3A%3AInformation)%3B%0A%20%20%20%20msgBox.move(QPoint(width()%2F2%2C%20height()%2F2)%20%2B%20QPoint(-100%2C%20-50))%3B%0A%20%20%20%20Qt%3A%3AWindowFlags%20flags%20%3D%20msgBox.windowFlags()%3B%0A%20%20%20%20msgBox.setWindowFlags(flags%20%5E%20Qt%3A%3AWindowSystemMenuHint)%3B%0A%0A%20%20%20%20if%20(!image)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20msgBox.setWindowTitle(tr(%22Close%20Map%22))%3B%0A%20%20%20%20%7D%0A%20%20%20%20else%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20msgBox.setWindowTitle(tr(%22Close%20Picture%22))%3B%0A%20%20%20%20%7D%0A%20%20%20%20msgBox.setText(tr(%22Do%20you%20want%20to%20close%20%251%20%252%3F%5CnIt%20will%20be%20closed%20for%20everybody%22).arg(mapImageTitle).arg(image%3Ftr(%22%22)%3Atr(%22(Map)%22)))%3B%0A%0A%20%20%20%20msgBox.exec()%3B%0A%20%20%20%20if%20(msgBox.result()%20!%3D%20QMessageBox%3A%3AYes)%0A%20%20%20%20%20%20%20%20return%3B%0A%0A%20%20%20%20if%20(!image)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20NetworkMessageWriter%20msg(NetMsg%3A%3AMapCategory%2CNetMsg%3A%3ACloseMap)%3B%0A%20%20%20%20%20%20%20%20msg.string8(mapImageId)%3B%0A%20%20%20%20%20%20%20%20msg.sendAll()%3B%0A%0A%20%20%20%20%20%20%20%20m_mapWindowMap.remove(mapImageId)%3B%0A%20%20%20%20%20%20%20%20m_playersListWidget-%3Emodel()-%3EchangeMap(NULL)%3B%0A%20%20%20%20%20%20%20%20m_toolBar-%3EchangeMap(NULL)%3B%0A%20%20%20%20%7D%0A%20%20%20%20else%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20NetworkMessageWriter%20msg(NetMsg%3A%3APictureCategory%2CNetMsg%3A%3ADelPictureAction)%3B%0A%20%20%20%20%20%20%20%20msg.string8(mapImageId)%3B%0A%20%20%20%20%20%20%20%20msg.sendAll()%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20MediaContainer*%20%20mediaContener%20%3D%20dynamic_cast(subactive)%3B%0A%20%20%20%20if(NULL!%3DmediaContener)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20CleverURI*%20cluri%20%3D%20mediaContener-%3EgetCleverUri()%3B%0A%20%20%20%20%20%20%20%20cluri-%3EsetDisplayed(false)%3B%0A%20%20%20%20%20%20%20%20if(NULL!%3Dm_sessionManager)%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20m_sessionManager-%3EupdateCleverUri(cluri)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%0A%20%20%20%20delete%20action%3B%0A%20%20%20%20delete%20subactive%3B%0A%7D%0A”/]

Then, we implements a solution to describe map, vmap (v1.8) or image as mediacontener.
They share a large part of their code, so it becomes really easy to do it.

[pastacode lang=”cpp” message=”Actuel” highlight=”” provider=”manual” manual=”QMdiSubWindow*%20subactive%20%3D%20m_mdiArea-%3EcurrentSubWindow()%3B%0A%20%20%20%20MediaContainer*%20container%20%3D%20dynamic_cast(subactive)%3B%0A%20%20%20%20if(NULL%20!%3D%20container)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20CleverURI%3A%3AContentType%20type%20%3D%20container-%3EgetContentType()%3B%0A%20%20%20%20%20%20%20%20if(CleverURI%3A%3AVMAP%20%3D%3D%20type)%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20removeVMapFromId(container-%3EgetMediaId())%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20else%20if(CleverURI%3A%3AMAP%20%3D%3D%20type)%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20removeMapFromId(container-%3EgetMediaId())%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20else%20if(CleverURI%3A%3APICTURE%20%3D%3D%20type%20)%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20removePictureFromId(container-%3EgetMediaId())%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A”/]

To prepare my conference at Pas Sage En Seine [FR], a French hacking festival, I chose to write my slide presentation in QML.
It allows me to have better control and be free to do whatever I want (such as a timeline or any kind of animation).
Of course, That comes with a price. It is longer to do it that way but now I find some solutions. So, next time will be faster.

File hierarchy:

I preferred use QML through C++ Application. It provides more helpful feature, such as: the ability to make screenshots of your presentation at any time (useful as backup plan).
At the top level, you will found all C++ classes, project files and the main qml. Then, you will have a directory with all your pages and if it is required a directory with all your images.

├── cpphighlighter.cpp
├── cpphighlighter.h
├── deployment.pri
├── LICENSE
├── main.cpp
├── main.qml
├── pages
│   ├── 01_intro.qml
│   ├── 02_presentation.qml
│   ├── 03_jdr_et_rolisteam.qml
│   ├── 043_Exemple_code_1.qml
│   ├── 04_jdr_avantages_pb.qml
│   ├── 05_avantage_jdr_virtuel.qml
│   ├── 06_fonctionnalites_rolisteam.qml
│   ├── 07_rolisteam_debut.qml
│   ├── 08_Rolistik_a_Rolisteam.qml
│   ├── 10_frise_chronologique.qml
│   ├── 11_son_usage.qml
│   ├── 12_son_fonctionnement.qml
│   ├── 13_dice_parser.qml
│   ├── 14_themes_audio_3_pistes.qml
│   ├── 15_nouveaute_1_8.qml
│   ├── 16_projet_avenir.qml
│   ├── 17_reussites.qml
│   ├── 18_les_lecons.qml
│   ├── 19_objectif_rolisteam_libre.qml
│   ├── 20_FAQ.qml
├── pasSageEnSeine.pro
├── pasSageEnSeine.pro.user
├── qmlcontroler.cpp
├── qmlcontroler.h
├── qmlcontroler.ui
├── qml.qrc
├── README.md
├── rsrc
│   ├── all.png
│   ├── cc.png
│   └── chat.png

The C++ application

The main

It can be useful to see the state of the presentation and to read some extra notes about the current slide. To manage that, I wrote a small C++ application.
The first goal is to show the QML view, then add some features and communication between the QML view and the C++ window.

[pastacode lang=”cpp” manual=”%23include%20%3CQApplication%3E%0A%23include%20%3CQQmlApplicationEngine%3E%0A%23include%20%22qmlcontroler.h%22%0A%23include%20%3CQQmlContext%3E%0A%23include%20%3CQQuickTextDocument%3E%0A%0A%23include%20%22cpphighlighter.h%22%0A%0Aint%20main(int%20argc%2C%20char%20*argv%5B%5D)%0A%7B%0A%20%20%20%20QApplication%20app(argc%2C%20argv)%3B%0A%0A%20%20%20%20QQmlApplicationEngine%20engine%3B%0A%0A%20%20%20%20engine.rootContext()-%3EsetContextProperty(%22ScreenW%22%2C1280)%3B%0A%20%20%20%20engine.rootContext()-%3EsetContextProperty(%22ScreenH%22%2C720)%3B%0A%0A%20%20%20%20engine.load(QUrl(QStringLiteral(%22qrc%3A%2Fmain.qml%22)))%3B%0A%0A%20%20%20%20QmlControler%20ctr%3B%0A%20%20%20%20ctr.setEngine(%26engine)%3B%0A%0A%20%20%20%20return%20app.exec()%3B%0A%7D%0A” message=”main.cpp” highlight=”” provider=”manual”/]

Really easy, it loads the main.qml from the resources management system provided by Qt. It defines the targeted resolution by setting two constant into QML word: ScreenW and ScreenH.

In this project, the QmlControler class is the C++ window which provides slide feedback and additional information.

Let’s take a look to it:

Feedback window

This window is really simple. It has two parts: On the left, there is a label which displays screenshot of the qml view, and the right part is a QTextArea which display any additional note about the current slide.

[pastacode lang=”cpp” manual=”void%20QmlControler%3A%3AcurrentPageHasChanged(int%20i)%0A%7B%0A%20%20%20%20m_currentScreen%20%3D%20i%3B%0A%20%20%20%20QImage%20img%20%3D%20m_window-%3EgrabWindow()%3B%0A%0A%20%20%20%20if(img.isNull())%0A%20%20%20%20%20%20%20%20return%3B%0A%0A%20%20%20%20static%20int%20count%20%3D%200%3B%0A%0A%0A%20%20%20%20img.save(tr(%22screens%2F%251_screen.png%22).arg(%2B%2Bcount%2C3%2C10%2CQChar(‘0’))%2C%22png%22)%3B%0A%20%20%20%20qDebug()%20%3C%3C%20%22screen%20shot%20save%22%20%3C%3C%20count%3B%0A%0A%20%20%20%20m_ratioImage%20%3D%20(double)img.size().width()%2Fimg.size().height()%3B%0A%20%20%20%20m_ratioImageBis%20%3D%20(double)img.size().height()%2Fimg.size().width()%3B%0A%0A%20%20%20%20m_label-%3EsetPixmap(QPixmap%3A%3AfromImage(img))%3B%0A%0A%20%20%20%20if((i%2B1%3E%3D0)%26%26(i%2B1%3Cm_commentData.size()))%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20ui-%3EtextEdit-%3EsetHtml(m_commentData.at(i%2B1))%3B%0A%20%20%20%20%7D%0A%20%20%20%20resizeLabel()%3B%0A%7D” message=”Current slide has changed” highlight=”” provider=”manual”/]

When the current slide has changed, the c++ window is notified thought the slot currentPageHasChanged, The application gets screenshot of the qml view, save it as a file, display it thought the label, then it looks for data about the current slide into the model. If any, there are displayed in the textedit.

Saving screenshots into file allows you to create a pdf file as backup plan for your presentation.

$ convert *.png mypresentation.pdf

 

QML Application

Loader system.

For readability reason, it is easier to have each page into one qml file. The application has to load those pages in the right order. To reach this goal, we have to define the order. I did it thank to a data model inside the main.qml file.
The main.qml displays all pages as item of a pathview. All items are loaded from the qt resource management system.

[pastacode lang=”css” manual=”ListModel%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20id%3A%20panelModel%0A%20%20%20%20%20%20%20%20%20%20%20%20ListElement%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20name%3A%20%22Intro%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20path%3A%20%2201_intro.qml%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20time%3A%201%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20next%3A%20%22Pr%C3%A9sentation%20de%20Rolisteam%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D” message=”First item of the model.” highlight=”” provider=”manual”/]

A page is mainly defined by two data: name and path. The path is the name of the qml file.
All other data are here as help, the time has not been used.

Then, the loader does its job, the key lines are the following:

[pastacode lang=”css” manual=”%20%20%20%20PathView%20%7B%0A%20%20%20%20%20%20%20%20id%3A%20view%0A%20%20%20%20%20%20%20%20anchors.fill%3A%20parent%0A%20%20%20%20%20%20%20%20model%3A%20panelModel%0A%20%20%20%20%20%20%20%20highlightRangeMode%3APathView.StrictlyEnforceRange%0A%20%20%20%20%20%20%20%20snapMode%3A%20PathView.SnapOneItem%0A%20%20%20%20%20%20%20%20delegate%3A%20%20Loader%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20source%3A%20%22pages%2F%22%2Bpath%0A%20%20%20%20%20%20%20%20%7D” message=”Path View” highlight=”source: “pages/”+path” provider=”manual”/]

 

Table of Contents

To manage the table of contents, I added a listview with a model:

[pastacode lang=”css” manual=”%20%20%20%20ListView%20%7B%0A%20%20%20%20%20%20%20%20id%3A%20listView1%0A%20%20%20%20%20%20%20%20x%3A%20ScreenW*0.02%0A%20%20%20%20%20%20%20%20y%3A%20ScreenH*0.3%0A%20%20%20%20%20%20%20%20width%3A%20ScreenW%2F2%0A%20%20%20%20%20%20%20%20height%3A%20ScreenH*0.2%0A%20%20%20%20%20%20%20%20delegate%3A%20Item%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20width%3A%20ScreenW%2F2%0A%20%20%20%20%20%20%20%20%20%20%20%20height%3A%20listView1.height%2FlistView1.count%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Text%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20color%3A%20view.currentIndex%3E%3Dindex%20%3F%20%22black%22%20%3A%20%22gray%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20text%3A%20name%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20font.pointSize%3A%20ScreenH%2F48%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20anchors.verticalCenter%3A%20parent.verticalCenter%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20font.bold%3A%20true%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20visible%3A%20view.currentIndex%3E0%20%3F%20true%20%3A%20false%0A%0A%20%20%20%20%20%20%20%20model%3A%20ListModel%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20ListElement%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20name%3A%20%22Concepts%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20index%3A1%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20ListElement%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20name%3A%20%22Chroniques%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20index%3A6%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20ListElement%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20name%3A%20%22Logiciel%22%2F%2Fsyst%C3%A8me%20de%20build%2C%20code%20sp%C3%A9cifique%20par%20OS.%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20index%3A9%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20ListElement%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20name%3A%20%22Bilan%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20index%3A15%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D” message=”Table of contents in QML ” highlight=”” provider=”manual”/]

Next slide

When you have many slides it can be helpful to have indication about the next one. I chose to display the title in the top-right corner. It was the easier way.

[pastacode lang=”css” manual=”%20%20%20%20Text%20%7B%0A%20%20%20%20%20%20%20%20anchors.top%3A%20parent.top%0A%20%20%20%20%20%20%20%20anchors.right%3A%20parent.right%0A%20%20%20%20%20%20%20%20text%3A%20panelModel.get(view.currentIndex).next%2B%22%3E%22%0A%20%20%20%20%7D” message=”Next slide” highlight=”” provider=”manual”/]

 

Design a page

Each page are independent but they are all based on the same pattern. In my case, they have a listview with model. Each item of the model is an point I should talk about it.

Each item has a index. The index is controlled with keyboard (down to increase, up to decrease). The page manages what is shown or hidden given the value of the index.

For example, the feature of dice alias has 10 as index. When the index page value becomes 10, the «Dice Alias»  item is displayed with an animation. Then, at 11, I can show a screen shot about the dice alias. At 12, the screenshot disappears and another text is displayed.

Position and Size

To ensure that all items will be display at the proper position and size.  I have based all computation on anchor or the screen size.

[pastacode lang=”css” manual=”%20%20%20%20Image%20%7B%0A%20%20%20%20%20%20%20%20id%3A%20image1%0A%20%20%20%20%20%20%20%20anchors.left%3A%20parent.left%0A%20%20%20%20%20%20%20%20anchors.top%3A%20parent.top%0A%20%20%20%20%20%20%20%20anchors.leftMargin%3A%20ScreenW*0.04%0A%20%20%20%20%20%20%20%20fillMode%3A%20Image.PreserveAspectFit%0A%20%20%20%20%20%20%20%20source%3A%20%22qrc%3A%2Frsrc%2FRolisteam.svg%22%0A%20%20%20%20%20%20%20%20width%3A%20ScreenW*0.2%0A%20%20%20%20%7D” message=”Display the logo at the right position and size.” highlight=”” provider=”manual”/]

Other way

There is a module that provides Items to create QML presentation. I don’t use it for this one but it may provide interesting things.

https://github.com/qt-labs/qml-presentation-system

Get the code

You are invited to clone the code at : https://github.com/obiwankennedy/pses