Commit 6b3e3ffc authored by David Boddie's avatar David Boddie 💬
Browse files

Merge branch 'add-pictures-example' into 'master'

Start documenting the pictures example

See merge request Librem5/!255
parents 000ed2ac 6092c251
Pipeline #5556 passed with stages
in 9 minutes and 44 seconds
......@@ -19,3 +19,6 @@
[submodule "Apps/Examples/General/Treasure/app"]
path = Apps/Examples/General/Treasure/app
url =
[submodule "Apps/Examples/Files/Pictures/app"]
path = Apps/Examples/Files/Pictures/app
url =
.. |main-file| replace:: ````
.. |executable| replace:: ``pictures``
.. |desktop-entry-in| replace:: ````
.. |desktop-entry| replace:: ````
.. |desktop-entry-ref| replace:: desktop entry file
.. |svg-file| replace:: ````
.. include:: /Apps/Examples/common/Building_the_App.txt
.. |project| replace::
.. |repo| replace:: pictures.git
.. |project-repo| replace:: ````
.. include:: /Apps/Examples/common/Getting_the_App.txt
.. |manifest| replace:: ````
.. |manifest-path| replace:: app/
.. |app-id| replace::
.. |extra-permissions-info| replace:: We also specify the ``--filesystem=xdg-pictures`` permission to request access to the user's *Pictures* directory, as described in the :ref:`flatpak_app_permissions_guide` guide.
.. include:: ../../common/Packaging_the_App.txt
.. _Files_Pictures_example_src:
Source Files
.. contents::
Most of the code for the application is included in a single ```` file which contains a single ``Application`` class to manage the running of the application and a ``main`` function to start it.
Much of the is very similar to other examples and tutorials. We will focus on the parts that are specific to this example.
Relevant Modules
Besides standard Python modules such as ``os`` and ``sys``, the ``Handy`` module helps us to create adaptive user interfaces. This module is imported in the same way as the ``Gtk`` module:
.. literalinclude:: app/src/
:language: python3
:start-at: import os
:end-at: Pages
The ``widgets`` module contains a helper class that we won't cover in any detail.
Setting up the User Interface
The ``Application`` class provides the usual methods to set up the application
and perform tasks when it is run.
In the ``do_startup`` method we define two parameters for the thumbnail dimensions:
.. literalinclude:: app/src/
:language: python3
:start-at: do_startup
:end-at: thumbnail_height
These are hard-coded in this example, but more complex applications would load these values from the application's settings.
In the ``do_activate`` method we set up the user interface, using a helper class to set up an adaptive user interface consisting of two leaflets: one in the window's header bar, the other in the main area of the window:
.. literalinclude:: app/src/
:language: python3
:start-at: do_activate
:end-at: show_all
The leaflet in the main area holds two pages: one with a list of thumbnails, the other with a simple image viewer.
.. figure:: images/pages.png
:scale: 50%
:align: center
:alt: The two pages of the application side by side
The two pages of the application side by side
For the first page we use a `Gtk.ScrolledWindow`_ widget to provide a scrolling list of thumbnails. The thumbnails are held by a `Gtk.ListStore`_ object that we create, specifying the data types it holds: a ``Pixbuf`` and a string that holds the file name of the image:
.. literalinclude:: app/src/
:language: python3
:start-at: def create_thumbnails_page
:end-at: load_thumbnails
We populate the model by calling the ``load_thumbnails`` method which we describe later.
The thumbnails are displayed by a `Gtk.IconView`_ widget, using the model as a data source, and mapping the fields in the model to columns in the view.
.. literalinclude:: app/src/
:language: python3
:start-at: Gtk.IconView
:end-at: return page
We also connect the ``item-activated`` signal to the ``show_details`` method to respond when the user clicks or touches a thumbnail.
The second page is also a `Gtk.ScrolledWindow`_ widget, but only contains a single `Gtk.Image`_ widget that initially contains the application's own icon:
.. literalinclude:: app/src/
:language: python3
:start-at: def create_details_page
:end-at: return page
As for the first page, we also return the widget that represents the page.
Loading and Displaying Images
The ``load_thumbnails`` method begins by locating the user's *Pictures* directory:
.. literalinclude:: app/src/
:language: python3
:start-at: def load_thumbnails
:end-at: GLib.UserDirectory.DIRECTORY_PICTURES
As described in the :ref:`gnome_settings_files` section of the :ref:`gnome_settings` guide, the ``GLib.get_user_special_dir`` function is used to obtain the path to the *Pictures* directory, specified using the ``DIRECTORY_PICTURES`` constant.
We iterate over the files in the directory, loading each of them at the size required for the thumbnails, and we add them to the model created in the ``create_thumbnails_page`` method:
.. literalinclude:: app/src/
:language: python3
:start-at: os.listdir(pictures_dir)
:end-at: self.model.append
Each thumbnail is added as a list of fields with types that correspond to the ones we specified when we created the `Gtk.ListStore`_ model.
The ``show_details`` method loads an image at its full size for display in the details page:
.. literalinclude:: app/src/
:language: python3
:start-at: def show_details
:end-at: self.pages.show_page
We use the `Gtk.TreePath`_ passed to this method, along with a `Gtk.TreeIter`_ object, to obtain the file name of the image from the model. A good introduction to this class is provided by the `Tree and List Widgets`_ chapter of the `Python GTK+ 3 Tutorial`_.
You can access files in specific directories in the user's home directory by calling the `GLib.get_user_special_dir`_ function to obtain the file paths you require. The directory you want to access is specified using a value from the `GLib.UserDirectory`_ enum.
In this case we use ``DIRECTORY_PICTURES`` to access the user's *Pictures* directory and load images using the `GdkPixbuf.Pixbuf`_ class, using the ``new_from_file_at_scale`` method for thumbnails and the ``new_from_file`` method for full size images.
Note that the ``load_thumbnails`` method will only return once all the images have been loaded. If the user has a large number of images in their *Pictures* directory then the user interface will be unresponsive when the application starts. We could use a background thread or some kind of lazy loading mechanism to make image loading appear quicker.
.. include:: /links.txt
.. _`Tree and List Widgets`:
.. _examples_Files_Pictures_summary:
Applications that need to access user directories call the `GLib.get_user_special_dir`_ function to find the location of the directory, passing the appropriate `GLib.UserDirectory`_ value for the specific directory.
When distributed as a flatpak, the manifest needs to contain the permission that :ref:`corresponds to the directory <flatpak_app_permissions_guide_table>` being accessed. In this case, the ``--filesystem=xdg-pictures`` permission allows the application to access the user's *Pictures* directory.
Images are loaded using the `GdkPixbuf.Pixbuf`_ class and typically displayed using the `Gtk.Image`_ widget. In this example we also used the `Gtk.IconView`_ widget to display image thumbnails.
.. include:: /links.txt
Subproject commit 4bb65b4b5bf83530b7ccd64d2a661edf34cc997f
.. _examples_Files_Pictures:
This example shows how to read image files from one of the user's directories and display their contents. When run, the application shows thumbnails of the images in a scrolling list. When a thumbnail is selected, a larger version of the images is displayed.
.. image:: images/screenshot.png
:scale: 50%
:align: center
:alt: A screenshot of the application running in the phone environment
We will focus on the parts of the application that are related to reading the image files and displaying their contents.
.. toctree::
:maxdepth: 1
.. include:: /links.txt
......@@ -19,7 +19,8 @@ development tools and libraries.
.. toctree::
:maxdepth: 1
.. include:: /links.txt
......@@ -27,6 +27,8 @@ More complex and larger data is also included in the user data directories by ap
Applications distributed as flatpaks do not need to request permissions in order to access user data stored in a data directory that has been set aside for that purpose.
.. _gnome_settings_files:
......@@ -20,6 +20,8 @@ example, each application can store and retrieve user data in its own private
area. This mechanism for storing persistent data is described in the section
about :ref:`gnome_settings_user_data`.
.. _flatpak_app_permissions_guide_table:
Permissions for Common Features
......@@ -15,6 +15,7 @@
.. _`Flatpak debugging documentation`:
.. _`Flatpak documentation`:
.. _`Freedesktop quick reference`:
.. _`GdkPixbuf.Pixbuf`:
.. _`Gio.GApplication documentation`:
.. _`git-buildpackage`:
.. _`GKeyFile`:
......@@ -22,6 +23,8 @@
.. _`Glade Tutorials`:
.. _`glib-compile-resources`:
.. _`g_get_user_data_dir`:
.. _`GLib.get_user_special_dir`:
.. _`GLib.UserDirectory`:
.. _`GMenu`:
.. _`GNOME API Reference`:
.. _`GNOME Builder`:
......@@ -39,21 +42,28 @@
.. _GtkApplication:
.. _`GtkApplicationWindow`:
.. _GtkBox:
.. _`Gtk.Box`:
.. _GtkBuilder:
.. _GtkButton :
.. _GtkGrid:
.. _GtkHeaderBar :
.. _`Gtk.IconView`:
.. _`Gtk.Image`:
.. _`GTK+ Inspector`:
.. _GtkLabel ellipsize property :
.. _GtkLabel :
.. _GtkLabel wrap-mode property :
.. _GtkLabel wrap property :
.. _GtkLabel xalign property :
.. _`Gtk.ListStore`:
.. _GtkMenuButton:
.. _GtkSeparator :
.. _GtkScrolledWindow :
.. _`Gtk.ScrolledWindow`:
.. _GtkSizeGroup :
.. _GtkToolButton :
.. _Gtk.TreeIter :
.. _Gtk.TreePath :
.. _`GTK+ toolkit`:
.. _`GTK+ website`:
.. _HdyHeaderGroup :
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment