[gtkmm/dropdown-demo] Demos: Add DropDown demo




commit 7fea7f029b4e885a223e5d4ab82499c0616d8ba5
Author: Andreas Persson <andreasp56 outlook com>
Date:   Sun Sep 20 12:00:39 2020 +0200

    Demos: Add DropDown demo

 demos/Makefile.am                  |   1 +
 demos/gtk-demo/demo.gresource.xml  |   1 +
 demos/gtk-demo/demos.h             |   2 +
 demos/gtk-demo/example_dropdown.cc | 288 +++++++++++++++++++++++++++++++++++++
 demos/gtk-demo/meson.build         |   1 +
 5 files changed, 293 insertions(+)
---
diff --git a/demos/Makefile.am b/demos/Makefile.am
index 23494c40..37b86205 100644
--- a/demos/Makefile.am
+++ b/demos/Makefile.am
@@ -41,6 +41,7 @@ GTK_DEMOS = \
   gtk-demo/example_colorsel.cc \
   gtk-demo/example_dialog.cc \
   gtk-demo/example_drawingarea.cc \
+  gtk-demo/example_dropdown.cc \
   gtk-demo/example_flowbox.cc \
   gtk-demo/example_gestures.cc \
   gtk-demo/example_glarea.cc \
diff --git a/demos/gtk-demo/demo.gresource.xml b/demos/gtk-demo/demo.gresource.xml
index 8d24adf1..a68c7d0b 100644
--- a/demos/gtk-demo/demo.gresource.xml
+++ b/demos/gtk-demo/demo.gresource.xml
@@ -42,6 +42,7 @@
     <file>example_colorsel.cc</file>
     <file>example_dialog.cc</file>
     <file>example_drawingarea.cc</file>
+    <file>example_dropdown.cc</file>
     <file>example_flowbox.cc</file>
     <file>example_gestures.cc</file>
     <file>example_glarea.cc</file>
diff --git a/demos/gtk-demo/demos.h b/demos/gtk-demo/demos.h
index 273c794e..e4c04614 100644
--- a/demos/gtk-demo/demos.h
+++ b/demos/gtk-demo/demos.h
@@ -18,6 +18,7 @@ Gtk::Window* do_builder();
 Gtk::Window* do_colorsel();
 Gtk::Window* do_dialog();
 Gtk::Window* do_drawingarea();
+Gtk::Window* do_dropdown();
 Gtk::Window* do_flowbox();
 Gtk::Window* do_gestures();
 Gtk::Window* do_glarea();
@@ -60,6 +61,7 @@ Demo testgtk_demos[] =
   { "Color Chooser", "example_colorsel.cc", sigc::ptr_fun(&do_colorsel), nullptr },
   { "Dialog and Message Boxes", "example_dialog.cc", sigc::ptr_fun(&do_dialog), nullptr },
   { "Drawing Area", "example_drawingarea.cc", sigc::ptr_fun(&do_drawingarea), nullptr },
+  { "Drop Downs", "example_dropdown.cc", sigc::ptr_fun(&do_dropdown), nullptr },
   { "Flow Box", "example_flowbox.cc",  sigc::ptr_fun(&do_flowbox), nullptr },
   { "Gestures", "example_gestures.cc",  sigc::ptr_fun(&do_gestures), nullptr },
   { "Header Bar", "example_headerbar.cc",  sigc::ptr_fun(&do_headerbar), nullptr },
diff --git a/demos/gtk-demo/example_dropdown.cc b/demos/gtk-demo/example_dropdown.cc
new file mode 100644
index 00000000..a96e4c1b
--- /dev/null
+++ b/demos/gtk-demo/example_dropdown.cc
@@ -0,0 +1,288 @@
+/* Drop Downs
+ *
+ * The Gtk::DropDown widget is a modern alternative to Gtk::ComboBox.
+ * It uses list models instead of tree models, and the content is
+ * displayed using widgets instead of cell renderers.
+ *
+ * The examples here demonstrate how to use different kinds of
+ * list models with Gtk::DropDown, how to use search and how to
+ * display the selected item differently from the presentation
+ * in the popup.
+ */
+
+#include <gtkmm.h>
+#include <pangomm/cairofontmap.h>
+
+class StringHolder : public Glib::Object {
+public:
+  Glib::ustring m_title;
+  std::optional<Glib::ustring> m_icon;
+  std::optional<Glib::ustring> m_description;
+protected:
+  StringHolder(const Glib::ustring& title,
+               const std::optional<Glib::ustring>& icon,
+               const std::optional<Glib::ustring>& description);
+public:
+  static Glib::RefPtr<StringHolder> create(
+    const Glib::ustring& title,
+    const std::optional<Glib::ustring>& icon,
+    const std::optional<Glib::ustring>& description);
+};
+
+StringHolder::StringHolder(const Glib::ustring& title,
+                           const std::optional<Glib::ustring>& icon,
+                           const std::optional<Glib::ustring>& description)
+:
+  m_title(title),
+  m_icon(icon),
+  m_description(description)
+{
+}
+
+Glib::RefPtr<StringHolder> StringHolder::create(
+  const Glib::ustring& title,
+  const std::optional<Glib::ustring>& icon,
+  const std::optional<Glib::ustring>& description)
+{
+  return Glib::make_refptr_for_instance<StringHolder>(
+    new StringHolder(title, icon, description));
+}
+
+
+class Example_DropDown : public Gtk::Window
+{
+public:
+  Example_DropDown();
+  ~Example_DropDown() override;
+
+protected:
+  void strings_setup_item_single_line(const Glib::RefPtr<Gtk::ListItem>& item);
+  void strings_setup_item_full(const Glib::RefPtr<Gtk::ListItem>& item);
+  void strings_bind_item(const Glib::RefPtr<Gtk::ListItem>& item);
+  Glib::RefPtr<Gtk::ListItemFactory> strings_factory_new(bool full);
+  Glib::RefPtr<Gio::ListModel> strings_model_new(const std::vector<Glib::ustring>& titles,
+                                                 const std::vector<Glib::ustring>& icons,
+                                                 const std::vector<Glib::ustring>& descriptions);
+  Gtk::DropDown* drop_down_new_from_strings(const std::vector<Glib::ustring>& titles,
+                                            const std::vector<Glib::ustring>& icons,
+                                            const std::vector<Glib::ustring>& descriptions);
+  Glib::ustring get_family_name(const Glib::RefPtr<Glib::ObjectBase>& item);
+  Glib::ustring get_title(const Glib::RefPtr<Glib::ObjectBase>& item);
+
+  Gtk::Box m_box;
+  Gtk::CheckButton m_check;
+};
+
+Gtk::Window* do_dropdown()
+{
+  return new Example_DropDown();
+}
+
+void Example_DropDown::strings_setup_item_single_line(const Glib::RefPtr<Gtk::ListItem>& item)
+{
+  auto box = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::HORIZONTAL, 10);
+
+  auto image = Gtk::make_managed<Gtk::Image>();
+  auto title = Gtk::make_managed<Gtk::Label>();
+  title->set_xalign(0.0);
+
+  box->append(*image);
+  box->append(*title);
+
+  item->set_data("title", title);
+  item->set_data("image", image);
+
+  item->set_child(*box);
+}
+
+void Example_DropDown::strings_setup_item_full(const Glib::RefPtr<Gtk::ListItem>& item)
+{
+  auto image = Gtk::make_managed<Gtk::Image>();
+  auto title = Gtk::make_managed<Gtk::Label>();
+  title->set_xalign(0.0);
+  auto description = Gtk::make_managed<Gtk::Label>();
+  description->set_xalign(0.0);
+  description->add_css_class("dim-label");
+
+  auto box = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::HORIZONTAL, 10);
+  auto box2 = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::VERTICAL, 2);
+
+  box->append(*image);
+  box->append(*box2);
+  box2->append(*title);
+  box2->append(*description);
+
+  item->set_data("title", title);
+  item->set_data("image", image);
+  item->set_data("description", description);
+
+  item->set_child(*box);
+}
+
+void Example_DropDown::strings_bind_item(const Glib::RefPtr<Gtk::ListItem>& item)
+{
+  auto holder = std::dynamic_pointer_cast<StringHolder>(item->get_item());
+
+  auto title = static_cast<Gtk::Label*>(item->get_data("title"));
+  auto image = static_cast<Gtk::Image*>(item->get_data("image"));
+  auto description = static_cast<Gtk::Label*>(item->get_data("description"));
+
+  title->set_label(holder->m_title);
+  if (image)
+  {
+    if (holder->m_icon)
+      image->set_from_icon_name(*holder->m_icon);
+    else
+      image->clear();
+    image->set_visible(holder->m_icon.has_value());
+  }
+  if (description)
+  {
+    description->set_label(*holder->m_description);
+    description->set_visible(holder->m_description.has_value());
+  }
+}
+
+Glib::RefPtr<Gtk::ListItemFactory> Example_DropDown::strings_factory_new(bool full)
+{
+  auto factory = Gtk::SignalListItemFactory::create();
+  if (full)
+    factory->signal_setup().connect(
+      sigc::mem_fun(*this, &Example_DropDown::strings_setup_item_full));
+  else
+    factory->signal_setup().connect(
+      sigc::mem_fun(*this, &Example_DropDown::strings_setup_item_single_line));
+  factory->signal_bind().connect(
+    sigc::mem_fun(*this, &Example_DropDown::strings_bind_item));
+
+  return factory;
+}
+
+Glib::RefPtr<Gio::ListModel> Example_DropDown::strings_model_new(
+  const std::vector<Glib::ustring>& titles,
+  const std::vector<Glib::ustring>& icons,
+  const std::vector<Glib::ustring>& descriptions)
+{
+  auto store = Gio::ListStore<StringHolder>::create();
+  for (guint i = 0; i < titles.size(); i++)
+  {
+    auto icon = icons.empty() ? std::nullopt : 
+      std::make_optional<Glib::ustring>(icons[i]);
+    auto description = descriptions.empty() ? std::nullopt :
+      std::make_optional<Glib::ustring>(descriptions[i]);
+    auto holder = StringHolder::create(titles[i], icon, description);
+    store->append(holder);
+  }
+
+  return store;
+}
+
+Gtk::DropDown* Example_DropDown::drop_down_new_from_strings(
+  const std::vector<Glib::ustring>& titles,
+  const std::vector<Glib::ustring>& icons,
+  const std::vector<Glib::ustring>& descriptions)
+{
+  g_return_val_if_fail(!titles.empty(), nullptr);
+  g_return_val_if_fail(icons.empty() || icons.size() == titles.size(), nullptr);
+  g_return_val_if_fail(descriptions.empty() || icons.size() == descriptions.size(), nullptr);
+
+  auto model = strings_model_new(titles, icons, descriptions);
+  auto factory = strings_factory_new(false);
+  Glib::RefPtr<Gtk::ListItemFactory> list_factory;
+  if (!icons.empty() || !descriptions.empty())
+    list_factory = strings_factory_new(true);
+
+  auto dropdown = Gtk::make_managed<Gtk::DropDown>(model);
+  dropdown->set_factory(factory);
+  dropdown->set_list_factory(list_factory);
+
+  return dropdown;
+}
+
+Glib::ustring Example_DropDown::get_family_name(const Glib::RefPtr<Glib::ObjectBase>& item)
+{
+  auto family = std::dynamic_pointer_cast<Pango::FontFamily>(item);
+  return family ? family->get_name() : "";
+}
+
+Glib::ustring Example_DropDown::get_title(const Glib::RefPtr<Glib::ObjectBase>& item)
+{
+  return std::dynamic_pointer_cast<StringHolder>(item)->m_title;
+}
+
+Example_DropDown::Example_DropDown()
+:
+  m_box(Gtk::Orientation::VERTICAL, 10),
+  m_check("Enable search")
+{
+  const std::vector<Glib::ustring> times{
+    "1 minute", "2 minutes", "5 minutes", "20 minutes"
+  };
+  const std::vector<Glib::ustring> many_times{
+    "1 minute", "2 minutes", "5 minutes", "10 minutes", "15 minutes", "20 minutes",
+    "25 minutes", "30 minutes", "35 minutes", "40 minutes", "45 minutes", "50 minutes",
+    "55 minutes", "1 hour", "2 hours", "3 hours", "5 hours", "6 hours", "7 hours",
+    "8 hours", "9 hours", "10 hours", "11 hours", "12 hours"
+  };
+  const std::vector<Glib::ustring> device_titles{
+    "Digital Output", "Headphones", "Digital Output", "Analog Output"
+  };
+  const std::vector<Glib::ustring> device_icons{
+    "audio-card-symbolic", "audio-headphones-symbolic", "audio-card-symbolic",
+    "audio-card-symbolic"
+  };
+  const std::vector<Glib::ustring> device_descriptions{
+    "Built-in Audio", "Built-in audio", "Thinkpad Tunderbolt 3 Dock USB Audio",
+    "Thinkpad Tunderbolt 3 Dock USB Audio"
+  };
+
+  set_title("Drop Downs");
+  set_resizable(false);
+
+  m_box.set_margin_start(10);
+  m_box.set_margin_end(10);
+  m_box.set_margin_top(10);
+  m_box.set_margin_bottom(10);
+  set_child(m_box);
+
+  auto model = Pango::CairoFontMap::get_default();
+  auto dropdown = Gtk::make_managed<Gtk::DropDown>(model);
+  dropdown->set_selected(0);
+
+  auto expression = Gtk::ClosureExpression<Glib::ustring>::create(
+    sigc::mem_fun(*this, &Example_DropDown::get_family_name));
+  dropdown->set_expression(expression);
+  m_box.append(*dropdown);
+
+  auto adj = Gtk::Adjustment::create(-1, -1, model->get_n_items());
+  auto spin = Gtk::make_managed<Gtk::SpinButton>(adj);
+  spin->set_halign(Gtk::Align::START);
+  Glib::Binding::bind_property(dropdown->property_selected(),
+                               spin->property_value(),
+                               Glib::Binding::Flags::SYNC_CREATE |
+                               Glib::Binding::Flags::BIDIRECTIONAL);
+  m_box.append(*spin);
+
+  Glib::Binding::bind_property(dropdown->property_enable_search(),
+                               m_check.property_active(),
+                               Glib::Binding::Flags::SYNC_CREATE |
+                               Glib::Binding::Flags::BIDIRECTIONAL);
+  m_box.append(m_check);
+
+  dropdown = drop_down_new_from_strings(times, {}, {});
+  m_box.append(*dropdown);
+
+  dropdown = drop_down_new_from_strings(many_times, {}, {});
+  dropdown->set_enable_search();
+  expression = Gtk::ClosureExpression<Glib::ustring>::create(
+    sigc::mem_fun(*this, &Example_DropDown::get_title));
+  dropdown->set_expression(expression);
+  m_box.append(*dropdown);
+
+  dropdown = drop_down_new_from_strings(device_titles, device_icons, device_descriptions);
+  m_box.append(*dropdown);
+}
+
+Example_DropDown::~Example_DropDown()
+{
+}
diff --git a/demos/gtk-demo/meson.build b/demos/gtk-demo/meson.build
index 4a5093b1..9850043d 100644
--- a/demos/gtk-demo/meson.build
+++ b/demos/gtk-demo/meson.build
@@ -12,6 +12,7 @@ gtkmm_demo_cc_files = [
   'example_colorsel.cc',
   'example_dialog.cc',
   'example_drawingarea.cc',
+  'example_dropdown.cc',
   'example_flowbox.cc',
   'example_gestures.cc',
   'example_glarea.cc',


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