[gtkmm: 1/2] Demos: Add listview application launcher demo




commit b021fea80d982bb1a9104c91e022286b07fdaa25
Author: Andreas Persson <andreasp56 outlook com>
Date:   Sat Sep 5 19:23:05 2020 +0200

    Demos: Add listview application launcher demo

 demos/Makefile.am                              |   1 +
 demos/gtk-demo/demo.gresource.xml              |   1 +
 demos/gtk-demo/demos.h                         |   7 +
 demos/gtk-demo/example_listview_applauncher.cc | 186 +++++++++++++++++++++++++
 demos/gtk-demo/meson.build                     |   1 +
 5 files changed, 196 insertions(+)
---
diff --git a/demos/Makefile.am b/demos/Makefile.am
index 483bd777..23494c40 100644
--- a/demos/Makefile.am
+++ b/demos/Makefile.am
@@ -48,6 +48,7 @@ GTK_DEMOS = \
   gtk-demo/example_iconbrowser.cc \
   gtk-demo/example_iconview.cc \
   gtk-demo/example_images.cc \
+  gtk-demo/example_listview_applauncher.cc \
   gtk-demo/example_overlay.cc \
   gtk-demo/example_panes.cc \
   gtk-demo/example_pixbufs.cc \
diff --git a/demos/gtk-demo/demo.gresource.xml b/demos/gtk-demo/demo.gresource.xml
index a55e0be4..8d24adf1 100644
--- a/demos/gtk-demo/demo.gresource.xml
+++ b/demos/gtk-demo/demo.gresource.xml
@@ -49,6 +49,7 @@
     <file>example_iconbrowser.cc</file>
     <file>example_iconview.cc</file>
     <file>example_images.cc</file>
+    <file>example_listview_applauncher.cc</file>
     <file>example_overlay.cc</file>
     <file>example_panes.cc</file>
     <file>example_pixbufs.cc</file>
diff --git a/demos/gtk-demo/demos.h b/demos/gtk-demo/demos.h
index 12bab82a..1a55eacd 100644
--- a/demos/gtk-demo/demos.h
+++ b/demos/gtk-demo/demos.h
@@ -25,6 +25,7 @@ Gtk::Window* do_headerbar();
 Gtk::Window* do_iconbrowser();
 Gtk::Window* do_iconview();
 Gtk::Window* do_images();
+Gtk::Window* do_listview_applauncher();
 Gtk::Window* do_overlay();
 Gtk::Window* do_panes();
 Gtk::Window* do_pixbufs();
@@ -46,6 +47,11 @@ Demo child0[] =
   { nullptr, nullptr, type_slotDo(), nullptr }
 };
 
+Demo child1[] =
+{
+  { "Application launcher", "example_listview_applauncher.cc", sigc::ptr_fun(&do_listview_applauncher), 
nullptr }
+};
+
 Demo testgtk_demos[] =
 {
   { "Application main window", "example_appwindow.cc", sigc::ptr_fun(&do_appwindow), nullptr },
@@ -59,6 +65,7 @@ Demo testgtk_demos[] =
   { "Icon Browser", "example_iconbrowser.cc", sigc::ptr_fun(&do_iconbrowser), nullptr },
   { "Icon View", "example_iconview.cc", sigc::ptr_fun(&do_iconview), nullptr },
   { "Images", "example_images.cc", sigc::ptr_fun(&do_images), nullptr },
+  { "Lists", "", type_slotDo(), child1 },
   { "OpenGL Area", "example_glarea.cc", sigc::ptr_fun(&do_glarea), nullptr },
   { "Overlay", "example_overlay.cc", sigc::ptr_fun(&do_overlay), nullptr },
   { "Paned Widgets", "example_panes.cc", sigc::ptr_fun(&do_panes), nullptr },
diff --git a/demos/gtk-demo/example_listview_applauncher.cc b/demos/gtk-demo/example_listview_applauncher.cc
new file mode 100644
index 00000000..9a2b9bbc
--- /dev/null
+++ b/demos/gtk-demo/example_listview_applauncher.cc
@@ -0,0 +1,186 @@
+/* Lists/Application launcher
+ *
+ * This demo uses the Gtk::ListView widget as a fancy application launcher.
+ *
+ * It is also a very small introduction to listviews.
+ */
+
+#include <gtkmm.h>
+#include <giomm/appinfo.h>
+#include <giomm/liststore.h>
+
+class Example_ListView_AppLauncher : public Gtk::Window
+{
+public:
+  Example_ListView_AppLauncher();
+  ~Example_ListView_AppLauncher() override;
+
+protected:
+  Glib::RefPtr<Gio::ListModel> create_application_list();
+  void setup_listitem(const Glib::RefPtr<Gtk::ListItem>& list_item);
+  void bind_listitem(const Glib::RefPtr<Gtk::ListItem>& list_item);
+  void activate(guint position);
+
+  Gtk::ListView* m_list;
+  std::unique_ptr<Gtk::MessageDialog> m_error_dialog;
+};
+
+Gtk::Window* do_listview_applauncher()
+{
+  return new Example_ListView_AppLauncher();
+}
+
+
+/* This is the function that creates the Gio::ListModel that we need.
+ * GTK list widgets need a Gio::ListModel to display, as models support change
+ * notifications.
+ * Unfortunately various older APIs do not provide list models, so we create
+ * our own.
+ */
+Glib::RefPtr<Gio::ListModel> Example_ListView_AppLauncher::create_application_list()
+{
+  /* We use a Gio::ListStore here, which is a simple array-like list implementation
+   * for manual management.
+   * List models need to know what type of data they provide, so we need to
+   * provide the type here. As we want to do a list of applications, Gio::AppInfo
+   * is the object we provide.
+   */
+  auto store = Gio::ListStore<Gio::AppInfo>::create();
+
+  for (auto app : Gio::AppInfo::get_all())
+    store->append(app);
+
+  return store;
+}
+
+/* This is the function we use for setting up new listitems to display.
+ * We add just an Gtk::Image and a Gtk::Label here to display the application's
+ * icon and name, as this is just a simple demo.
+ */
+void Example_ListView_AppLauncher::setup_listitem(const Glib::RefPtr<Gtk::ListItem>& list_item)
+{
+  auto box = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::HORIZONTAL, 12);
+  auto image = Gtk::make_managed<Gtk::Image>();
+  image->set_icon_size(Gtk::IconSize::LARGE);
+  box->append(*image);
+  auto label = Gtk::make_managed<Gtk::Label>();
+  box->append(*label);
+  list_item->set_child(*box);
+}
+
+/* Here we need to prepare the listitem for displaying its item. We get the
+ * listitem already set up from the previous function, so we can reuse the
+ * Gtk::Image widget we set up above.
+ * We get the item - which we know is a Gio::AppInfo because it comes out of
+ * the model we set up above, grab its icon and display it.
+ */
+void Example_ListView_AppLauncher::bind_listitem(const Glib::RefPtr<Gtk::ListItem>& list_item)
+{
+  if (auto image = dynamic_cast<Gtk::Image*>(list_item->get_child()->get_first_child()))
+    if (auto label = dynamic_cast<Gtk::Label*>(image->get_next_sibling()))
+      if (auto app_info = std::dynamic_pointer_cast<Gio::AppInfo>(list_item->get_item()))
+      {
+        image->set(app_info->get_icon());
+        label->set_label(app_info->get_display_name());
+      }
+}
+
+/* In more complex code, we would also need functions to unbind and teardown
+ * the listitem, but this is simple code, so the default implementations are
+ * enough. If we had connected signals, this step would have been necessary.
+ *
+ * The Gtk::SignalListItemFactory documentation contains more information about
+ * this step.
+ */
+
+/* This function is called whenever an item in the list is activated. This is
+ * the simple way to allow reacting to the Enter key or double-clicking on a
+ * listitem.
+ * Of course, it is possible to use far more complex interactions by turning
+ * off activation and adding buttons or other widgets in the setup function
+ * above, but this is a simple demo, so we'll use the simple way.
+ */
+void Example_ListView_AppLauncher::activate(guint position)
+{
+  auto item = std::dynamic_pointer_cast<Gio::ListModel>(m_list->get_model())->get_object(position);
+  if (auto app_info = std::dynamic_pointer_cast<Gio::AppInfo>(item))
+  {
+    /* Prepare the context for launching the application and launch it. This
+     * code is explained in detail in the documentation for Gdk::AppLaunchContext
+     * and Gio::AppInfo.
+     */
+    auto context = m_list->get_display()->get_app_launch_context();
+    try
+    {
+      app_info->launch(std::vector<Glib::RefPtr<Gio::File>>(), context);
+    }
+    catch (const Glib::Error& error)
+    {
+      /* And because error handling is important, even a simple demo has it:
+       * We display an error dialog that something went wrong.
+       */
+      if (!m_error_dialog)
+      {
+        m_error_dialog.reset(new Gtk::MessageDialog(
+          *this, "", false, Gtk::MessageType::ERROR, Gtk::ButtonsType::CLOSE, true));
+        m_error_dialog->set_hide_on_close();
+        m_error_dialog->signal_response().connect(
+          sigc::hide(sigc::mem_fun(*m_error_dialog, &Gtk::Widget::hide)));
+      }
+      m_error_dialog->set_message(
+        Glib::ustring::sprintf("Could not launch %s", app_info->get_display_name()));
+      m_error_dialog->set_secondary_text(error.what());
+      m_error_dialog->show();
+    }
+  }
+}
+
+Example_ListView_AppLauncher::Example_ListView_AppLauncher()
+{
+  set_default_size(640, 320);
+  set_title("Application Launcher");
+
+  /* The Gtk::ListItemFactory is what is used to create Gtk::ListItems
+   * to display the data from the model. So it is absolutely necessary
+   * to create one.
+   * We will use a Gtk::SignalListItemFactory because it is the simplest
+   * one to use. Different ones are available for different use cases.
+   * The most powerful one is Gtk::BuilderListItemFactory which uses
+   * Gtk::Builder .ui files, so it requires little code.
+   */
+  auto factory = Gtk::SignalListItemFactory::create();
+  factory->signal_setup().connect(
+    sigc::mem_fun(*this, &Example_ListView_AppLauncher::setup_listitem));
+  factory->signal_bind().connect(
+    sigc::mem_fun(*this, &Example_ListView_AppLauncher::bind_listitem));
+
+  /* And of course we need to set the data model. Here we call the function
+   * we wrote above that gives us the list of applications. Then we set
+   * it on the list widget.
+   * The list will now take items from the model and use the factory
+   * to create as many listitems as it needs to show itself to the user.
+   */
+  auto model = create_application_list();
+
+  /* Create the list widget here.
+   */
+  m_list = Gtk::make_managed<Gtk::ListView>(Gtk::SingleSelection::create(model), factory);
+
+  /* We connect the activate signal here. It's the function we defined
+   * above for launching the selected application.
+   */
+  m_list->signal_activate().connect(
+    sigc::mem_fun(*this, &Example_ListView_AppLauncher::activate));
+
+  /* List widgets should always be contained in a Gtk::ScrolledWindow,
+   * because otherwise they might get too large or they might not
+   * be scrollable.
+   */
+  auto sw = Gtk::make_managed<Gtk::ScrolledWindow>();
+  set_child(*sw);
+  sw->set_child(*m_list);
+}
+
+Example_ListView_AppLauncher::~Example_ListView_AppLauncher()
+{
+}
diff --git a/demos/gtk-demo/meson.build b/demos/gtk-demo/meson.build
index 6e60c2b3..4a5093b1 100644
--- a/demos/gtk-demo/meson.build
+++ b/demos/gtk-demo/meson.build
@@ -19,6 +19,7 @@ gtkmm_demo_cc_files = [
   'example_iconbrowser.cc',
   'example_iconview.cc',
   'example_images.cc',
+  'example_listview_applauncher.cc',
   'example_overlay.cc',
   'example_panes.cc',
   'example_pixbufs.cc',


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]