Développer pour le Librem 5 [part 7] – Modularisation du template part 2

de | décembre 14, 2019

Attaquons-nous maintenant à l’ajout de la partie centrale de notre application qui contiendra notre contenu. Nous allons procéder de la même manière que pour la barre de titre. Je vais donc aller plus vite sûr les explications.

Fichier Template ui/content.ui

<?xml version="1.0" encoding="UTF-8"?>
<interface>
  <object class="GtkImage" id="help-icon">
    <property name="visible">True</property>
    <property name="can_focus">False</property>
    <property name="icon_name">help-faq-symbolic</property>
    <property name="icon_size">1</property>
  </object>
  <object class="GtkImage" id="home-icon">
    <property name="visible">True</property>
    <property name="can_focus">False</property>
    <property name="icon_name">go-home-symbolic</property>
    <property name="icon_size">1</property>
  </object>
  <object class="GtkImage" id="movie-icon">
    <property name="visible">True</property>
    <property name="can_focus">False</property>
    <property name="icon_name">video-display-symbolic</property>
    <property name="icon_size">1</property>
  </object>
  <object class="GtkImage" id="music-icon">
    <property name="visible">True</property>
    <property name="can_focus">False</property>
    <property name="icon_name">audio-x-generic-symbolic</property>
    <property name="icon_size">1</property>
  </object>
  <object class="GtkImage" id="remote-icon">
    <property name="visible">True</property>
    <property name="can_focus">False</property>
    <property name="icon_name">emoji-objects-symbolic</property>
    <property name="icon_size">1</property>
  </object>
  <object class="GtkImage" id="serie-icon">
    <property name="visible">True</property>
    <property name="can_focus">False</property>
    <property name="icon_name">video-joined-displays-symbolic</property>
    <property name="icon_size">1</property>
  </object>
  <object class="GtkImage" id="setting-icon">
    <property name="visible">True</property>
    <property name="can_focus">False</property>
    <property name="icon_name">applications-system-symbolic</property>
    <property name="icon_size">1</property>
  </object>
  <template parent="HdyLeaflet" class="Content">
    <property name="visible">True</property>
    <property name="can_focus">False</property>
    <property name="visible_child">stackContent</property>
    <property name="mode_transition_type">slide</property>
    <property name="child_transition_type">slide</property>
    <child>
      <object class="GtkBox" id="sidebarMenu">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <property name="orientation">vertical</property>
        <child>
          <object class="GtkButton" id="home-menu">
            <property name="label" translatable="yes" context="Home button">home</property>
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="receives_default">True</property>
            <property name="image">home-icon</property>
            <property name="relief">none</property>
            <property name="always_show_image">True</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">0</property>
          </packing>
        </child>
        <child>
          <object class="GtkButton" id="movie-menu">
            <property name="label" translatable="yes" context="Movie menu button">movie</property>
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="receives_default">True</property>
            <property name="image">movie-icon</property>
            <property name="relief">none</property>
            <property name="always_show_image">True</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">1</property>
          </packing>
        </child>
        <child>
          <object class="GtkButton" id="serie-menu">
            <property name="label" translatable="yes" context="Series menu button">serie</property>
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="receives_default">True</property>
            <property name="image">serie-icon</property>
            <property name="relief">none</property>
            <property name="always_show_image">True</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">2</property>
          </packing>
        </child>
        <child>
          <object class="GtkButton" id="music-menu">
            <property name="label" translatable="yes" context="Series menu button">music</property>
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="receives_default">True</property>
            <property name="image">music-icon</property>
            <property name="relief">none</property>
            <property name="always_show_image">True</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">3</property>
          </packing>
        </child>
        <child>
          <object class="GtkButton" id="remote-menu">
            <property name="label" translatable="yes" context="Series menu button">remote</property>
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="receives_default">True</property>
            <property name="image">remote-icon</property>
            <property name="relief">none</property>
            <property name="always_show_image">True</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">4</property>
          </packing>
        </child>
        <child>
          <object class="GtkSeparator">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">5</property>
          </packing>
        </child>
        <child>
          <object class="GtkButton" id="settings-menu">
            <property name="label" translatable="yes" context="Series menu button">settings</property>
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="receives_default">True</property>
            <property name="hexpand">False</property>
            <property name="image">setting-icon</property>
            <property name="relief">none</property>
            <property name="always_show_image">True</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">6</property>
          </packing>
        </child>
        <child>
          <object class="GtkButton" id="help-menu">
            <property name="label" translatable="yes" context="Help and aboutmenu button">help</property>
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="receives_default">True</property>
            <property name="image">help-icon</property>
            <property name="relief">none</property>
            <property name="always_show_image">True</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">7</property>
          </packing>
        </child>
      </object>
    </child>
    <child>
      <object class="GtkSeparator" id="separator_content">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <style>
          <class name="sidebar"/>
        </style>
      </object>
      <packing>
        <property name="name">separator</property>
      </packing>
    </child>
    <child>
      <object class="GtkStack" id="stackContent">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <property name="transition_type">crossfade</property>
        <child>
          <object class="GtkLabel">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="label" translatable="yes">page 1</property>
          </object>
          <packing>
            <property name="name">home</property>
            <property name="title" translatable="yes">home</property>
          </packing>
        </child>
        <child>
          <object class="GtkLabel">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="label" translatable="yes">label</property>
          </object>
          <packing>
            <property name="name">page1</property>
            <property name="title" translatable="yes">page1</property>
            <property name="position">1</property>
          </packing>
        </child>
        <child>
          <object class="GtkLabel">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="label" translatable="yes">label</property>
          </object>
          <packing>
            <property name="name">page2</property>
            <property name="title" translatable="yes">page2</property>
            <property name="position">2</property>
          </packing>
        </child>
        <child>
          <object class="GtkLabel">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="label" translatable="yes">label</property>
          </object>
          <packing>
            <property name="name">page3</property>
            <property name="title" translatable="yes">page3</property>
            <property name="position">3</property>
          </packing>
        </child>
        <child>
          <object class="GtkLabel">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="label" translatable="yes">label</property>
          </object>
          <packing>
            <property name="name">page4</property>
            <property name="title" translatable="yes">page4</property>
            <property name="position">4</property>
          </packing>
        </child>
        <child>
          <object class="GtkLabel">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="label" translatable="yes">label</property>
          </object>
          <packing>
            <property name="name">page5</property>
            <property name="title" translatable="yes">page5</property>
            <property name="position">5</property>
          </packing>
        </child>
        <child>
          <object class="GtkLabel">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="label" translatable="yes">label</property>
          </object>
          <packing>
            <property name="name">page6</property>
            <property name="title" translatable="yes">page6</property>
            <property name="position">6</property>
          </packing>
        </child>
      </object>
    </child>
    <child>
      <placeholder/>
    </child>
  </template>
</interface>

Ligne 1 et 2 nous déclarons notre fichier comme fichier template.

Ligne 47 nous prenons notre composant HdyLeaflet comme composant parent.

A noté aussi l’inclusion des composants GtkImage nécessaire aux boutons. Ceux-ci ne sont étrangement pas trouvé si laissé dans le fichier window.ui. Je vais essayer de trouver une méthode afin de rendre cela générique, car je ne me vois pas redéfinir les mêmes images dans chaque template les utilisant.

Fichier composant ui/content.js

#!/usr/bin/gjs
const { GObject, Handy } = imports.gi;

var Content = GObject.registerClass({
    GTypeName: 'Content',
    Template: 'resource:///info/scandi/kodimote/ui/content.ui',
    InternalChildren: []
}, class Content extends Handy.Leaflet {

  _init(params) {
    super._init(params);
  }
});

Rien de particulier. On définit notre fichier template ainsi que la classe parente (Handy.Leaflet).

Référencement des fichiers

src/info.scandi.kodimote.data.gresource.xml

<?xml version="1.0" encoding="UTF-8"?>
<gresources>
  <gresource prefix="/info/scandi/kodimote">
    <file>window.ui</file>
    <file>ui/titlebar.ui</file>
    <file>ui/content.ui</file>
  </gresource>
</gresources>

src/info.scandi.kodimote.src.gresource.xml

<?xml version="1.0" encoding="UTF-8"?>
<gresources>
  <gresource prefix="/info/scandi/kodimote/js">
    <file>main.js</file>
    <file>window.js</file>
    <file>ui/titlebar.js</file>
    <file>ui/content.js</file>
  </gresource>
</gresources>

Instanciation dans window.js

#!/usr/bin/gjs
var { GObject, Gtk } = imports.gi;
var { Titlebar } = imports.ui.titlebar;
var { Content } = imports.ui.content;

var KodimoteWindow = GObject.registerClass({
    GTypeName: 'KodimoteWindow',
    Template: 'resource:///info/scandi/kodimote/window.ui'
}, class KodimoteWindow extends Gtk.ApplicationWindow {
    _init(application) {
        super._init({ application });
        const titlebar = new Titlebar();
        this.set_titlebar(titlebar);
        const content = new Content()
        this.add(content);
    }
});

On importe notre composant Content, On l’instancie et on l’ajoute à notre fenêtre principale. Si on construit le projet, on obtient ceci :

GtkGroupSize

Dans l’article précédent, j’avais volontairement laissé en suspend l’erreur suivante :

Error building template class 'KodimoteWindow' for an instance of type 'KodimoteWindow': .:50:38 Object with ID sidebarHeader not found

Nous allons maintenant la corriger en instanciant nos composants GtkGroupSize après nos composants Content et Titlebar. Dans un premier temps, j’ai essayé de définir ces éléments dans leurs propres fichiers .ui. Seulement impossible de les faire prendre en compte, car si vous regarder bien ces deux composants ne sont pas a ajouter à notre fenêtre principale. Je corrigerais cet article dès que j’aurai la solution.

En attendant voici la solution de manière programmatique. Dans notre fichier window.js nous allons ajouter le code suivant :

const headerGroup = new Gtk.SizeGroup();
headerGroup.set_mode(Gtk.SizeGroupMode.HORIZONTAL);
headerGroup.add_widget(titlebar.sidebarHeader);
headerGroup.add_widget(content.sidebarMenu);

const contentGroup = new Gtk.SizeGroup();
contentGroup.set_mode(Gtk.SizeGroupMode.HORIZONTAL);
contentGroup.add_widget(titlebar.mainHeader);
contentGroup.add_widget(content.stackContent);

Ligne 1 nous instancions notre GtkGroupSize. Ligne 2 nous définissons le mode à horizontal puis nous ajountons nos widgets à synchroniser. Il nous reste à récupérer nos fameux widgets depuis nos composants Content et Titlebar. Onvrons le fichier titlebar.js et modifions le comme ceci :

#!/usr/bin/gjs
const { GObject, Handy } = imports.gi;

var Titlebar = GObject.registerClass({
    GTypeName: 'Titlebar',
    Template: 'resource:///info/scandi/kodimote/ui/titlebar.ui',
    InternalChildren: [
        'sidebarHeader',
        'mainHeader'
    ]
}, class Titlebar extends Handy.TitleBar {

  _init(params) {
    super._init(params);
  }

  on_menu_clicked() {
  }

  get sidebarHeader() {
    return this._sidebarHeader;
  }

  get mainHeader() {
    return this._mainHeader;
  }
});

C’est là qu’intervient notre fameux tableau InternalChildren en définissant les éléments de notre template auxquels nous voulons avoir accès. Gjs nous permet de récupérer ces éléments sous la forme this._[id_element]. C’est ce que nous faisons avec les méthodes sidebarHeader et mainHeader. A noter la méthode on_menu_clicked qui doit être reliée à un signal de notre titlebar. La définir permet d’éviter un warning à la compilation. Nous nous y intéresserons plus tard.

Faisons la même chose avec le composant content.js

#!/usr/bin/gjs
const { GObject, Handy } = imports.gi;

var Content = GObject.registerClass({
    GTypeName: 'Content',
    Template: 'resource:///info/scandi/kodimote/ui/content.ui',
    InternalChildren: [
        'sidebarMenu',
        'stackContent'
    ]
}, class Content extends Handy.Leaflet {

  _init(params) {
    super._init(params);
  }

  get sidebarMenu() {
    return this._sidebarMenu;
  }

  get stackContent() {
    return this._stackContent;
  }
});

Voila, si vous compilez, vous devriez avoir de nouveau la même interface qu’a la fin de l’article 5, sauf que cette fois nous avons modularisé tout cela. Ce qui est quand même bien meilleur.

00

Une réflexion au sujet de « Développer pour le Librem 5 [part 7] – Modularisation du template part 2 »

  1. Ping : Développer pour le Librem 5 [part 1] – Installation – Le blog de Scandi

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.