Darktable a sa propre bibliothèque d’objets GUI, pour les curseurs et les comboboxes (alias menus déroulants ou boîtes de sélection), appelée Bauhaus (dans le code source, c’est dans src/bauhaus/bauhaus.c
). Bien qu’ils utilisent Gtk en tant que moteur arrière, les objets Bauhaus sont des objets personnalisés. Et comme beaucoup de choses dans Darktable, personnaliser signifie pourri.
En 2022, j’ai remarqué des redessinages parasites et des lenteurs , lors de leur utilisation, conduisant à une expérience utilisateur frustrante : le redessinage des widgets semblait attendre la conclusion des recalculs de la chaîne, ce qui signifiait que les utilisateurs n’étaient pas vraiment sûrs que leur changement de valeur était pris en compte, ce qui pouvait les amener à réessayer, déclenchant un autre cycle de recalcul coûteux, et gelant effectivement leur ordinateur pendant plusieurs minutes frustrantes d’intermédiaires coûteux recalculs de la chaîne.
Comme cela arrive, les outils d’analyse de code statique trouve que la bibliothèque Bauhaus trouve le 4e plus complexe fichier source du code dans tout le logiciel Darktable en termes de complexité cyclomatique, avec un score de 735 et une dette technique estimée à 1 jour et 7 heures. Si vous n’êtes pas programmeur, la complexité cyclomatique mesure le nombre de chemins différents que le code peut prendre, et les valeurs élevées le rendent non seulement plus difficile à comprendre ( et donc à déboguer), mais aussi plus susceptible d’avoir des cas limites, des bugs et des problèmes bizarres dépendants du contexte. La complexité cyclomatique est une métrique indirecte de la probabilité que ce code explose en votre visage lorsque vous vous y attendez le moins, quelque chose à prendre en compte lorsque les “développeurs” les plus prolifiques dans votre équipe sont un enseignant du primaire, un pédiatre et un consultant bancaire.
Ce qui est particulièrement frustrant, c’est que j’ai déjà travaillé pour simplifier ce fichier, en 2019. 3 ans plus tard, c’était comme si je n’avais rien fait, grâce au feature creep et au support MIDI/joystick. Lorsque les redessinages parasites sont apparus, je me suis retrouvé avec un code spaghetti complètement indéchiffrable que j’étais proprement incapable de corriger. Une première tentative de correction de mauvaises choses a conduit à une impasse, en août 2022, et m’a découragé. Essayons de contourner le problème n’allait pas suffire.
J’ai donc dû le réécrire presque complètement, ce qui n’était pas amusant et m’a pris une quantité de temps folle (j’ai arrêté de compter à 3 semaines, à temps plein, et c’était pour la deuxième tentative d’août à novembre 2023).
Saviez-vous qu’une fois qu’une liste déroulante avait le focus (soit parce que vous avez cliqué dessus, soit parce que vous lui avez donné le focus via un raccourci clavier), vous pouviez commencer à taper les premières lettres de l’étiquette que vous vouliez sélectionner et elle sélectionnait automatiquement l’élément le plus proche de la liste ? Moi non plus avant d’entreprendre cette tâche, car c’est documenté nulle part. Comme beaucoup de fonctionnalités cachées là-bas, ajoutées pour se conformer aux cas d’utilisation déviants et marginaux, mais complexifiant la structure de code pour tout le monde. (Spoiler alert : j’ai gardé cette fonctionnalité particulière, mais en ai supprimé d’autres).
Liste des améliorations"
- Les coordonnées du curseur (dans les popup) sont calculées à un seul endroit, puis stockées. Cela permet d’économiser de nombreux recalculs intermédiaires, certains étant incohérents car le code avait été copié-collé et dupliqué au lieu d’utiliser les accesseurs . Désormais, les décalages et changements de coordonnées sont gérés par des accesseurs unifiés, ce qui signifie que tout changement futur ne devra se produire qu’à un seul endroit, et le code entier l’utilisera.
- Les nouvelles valeurs (provenant des curseurs et des listes déroulantes) ne sont plus dispatchées dans le pipeline de pixels pendant le défilement ou le glisser-déposer, mais uniquement à la fin. Cela repose sur un délai d’apprentissage machine enregistrant le temps moyen nécessaire pour calculer un pipeline complet. L’interface utilisateur attendra de 20 ms à 2,5 s pour dispatcher les changements au pipeline, évitant de recalculer à chaque étape de défilement ou de glisser, ce qui entraîne des calculs inutiles et redondants mais coûteux qui ralentissent le logiciel. De même, ils ne sont désormais dispatchés que lors de l’événement de relâchement du bouton, au lieu des événements de pression et de relâchement du bouton (étant donné qu’un clic de souris typique envoie les deux événements). Cela devrait éviter pas mal de recalculs inutiles du pipeline.
- Les widgets sont redessinés immédiatement lors des événements utilisateur, avant que les nouvelles valeurs ne soient dispatchées vers le pipeline de pixels. Cela garantit un retour immédiat à l’utilisateur, même si le résultat final en pixels peut survenir plus tard, et limite la frustration sur les ordinateurs lents.
- Ne pas dispatcher d’événements de changement de valeur si les widgets ont reçu une interaction de l’utilisateur mais que leur valeur n’a pas réellement changé.
- Capturer les clics sur le chevron (flèche droite) des listes déroulantes. Auparavant, il fallait cliquer sur l’étiquette pour dérouler le menu déroulant de la liste, ce qui était très frustrant si vous veniez d’un logiciel avec une interface utilisateur correcte. Le chevron lui-même ne répondait pas aux clics.
- Ne pas faire défiler les listes déroulantes. Cette fonctionnalité a commencé comme un projet cool : aligner l’élément actuellement sélectionné avec l’étiquette. Le problème est que le positionnement des fenêtres déroulantes est finalement géré par l’environnement de bureau, nous ne pouvons que lui demander poliment de faire ce que nous souhaitons, mais rien ne garantit que nos souhaits seront honorés. De plus, il est possible de faire rouler la fenêtre contextuelle hors du viewport, rien ne l’empêche. Tout compte fait, c’est fragile et aléatoire, mieux vaut rester avec le positionnement par défaut des fenêtres.
Fonctionnalités obsolètes
La possibilité d’assigner des raccourcis clavier aux curseurs et aux listes déroulantes est pour l’instant supprimée. Les curseurs et les listes déroulantes sont de toute façon liés aux touches fléchées et au défilement de la souris une fois qu’ils ont le focus1, et il est toujours possible d’assigner la capture de focus à un raccourci clavier. La logique actuelle est donc de demander le focus via des raccourcis clavier, puis de modifier la valeur à l’aide des touches fléchées. Les demandes de focus rendent également automatiquement le widget visible dans l’interface utilisateur, en défilant la barre latérale si nécessaire.
De toute façon, le système de raccourcis actuel devra être entièrement remplacé par des accélérateurs natifs de Gtk, qui sont déjà utilisés pour le menu global (et ont été utilisés dans Darktable avant 2021). Actuellement, nous avons deux systèmes, l’un d’eux étant une monstruosité de complexité et probablement responsable de ralentissements. KISS.
Avertissements
Le combobox «format» dans le module d’exportation n’initialise pas correctement sa valeur. Il s’agit d’un widget Bauhaus non standard qui nécessite une attention particulière. Pour l’instant, vous devrez actualiser l’option de stockage ou recharger un préréglage.
Chaque fois que vous supprimez l’ancienne peinture écaillée qui tenait les murs rouillés, vous risquez de faire des dommages collatéraux. Soyez prudent avec Ansel lors de l’utilisation du fichier AppImage et Win EXE étiqueté Ansel-57ed58d de ce soir et signalez tout ce qui semble étrange.
Téléchargements
Détails techniques
Les changements actuels ont permis de réduire :
- la complexité cyclomatique de 735 à 494
- la complexité cognitive de 796 à 432
- la dette technique de 1 jour et 7 heures à 4 heures et 50 minutes.
Si vous n’êtes pas programmeur, ces métriques signifient simplement que le code sera plus facile et moins chronophage à maintenir à l’avenir, et probablement moins sujet aux bogues.
Translated from English by : Aurélien Pierre, ChatGPT. In case of conflict, inconsistency or error, the English version shall prevail.
In GUI programming, a widget has the focus when it is the one recording keyboard events. Text entries are the most obvious example, but Darktable hacked that concept to generalize to pretty much every widget. ↩︎