TouchSelector

A Hildon::TouchSelector widget shows rows of information that can be panned, allowing the user to select one item. It can be associated with a Hildon::PickerButton, which will show the TouchSelector inside a Hildon::PickerDialog when the button is clicked.

Each column (TouchSelector::Column may contain multiple CellRenderers, just like a Gtk::ComboBox, or Gtk::TreeView::Column, allowing you to show detailed text, numbers, or pictures for each row.

The TouchSelector can also show multiple independently-pannable columns, each showing a separate Gtk::TreeModel, for instance when selecting the hour and minutes in the Hildon::TimeSelector widget. However, this is rarely necessary.

TouchSelector reference

The TouchSelectorText class offers a simpler API for showing a simple list of text strings.

TouchSelectorText reference

The derived TimeSelector and DateSelector widgets use multiple pannable columns to allow the user to specify a time or date, but these widgets are normally only used via the TimeButton and DateButton widgets.

Single-Column TouchSelector Example

This example shows a simple window that contains a Hildon::PickerButton. When clicked, the PickerButton shows a TouchSelector with one pannable column, showing rows from a Gtk::TreeModel. The column contains multiple CellRenderers, each displaying a column from the TreeModel, allowing each TouchSelector row to display more information about each item.

When a name is selected, the result appears as the value (sub-title) of the PickerButton and the application sends a line of output to the terminal.

Figure 4.8. Single-Column TouchSelector

Single-Column TouchSelector

Source Code

File: examplewindow.h

#ifndef _MAEMOMM_EXAMPLEWINDOW_H
#define _MAEMOMM_EXAMPLEWINDOW_H

#include <hildonmm/window.h>
#include <hildonmm/picker-button.h>
#include <hildonmm/touch-selector.h>
#include <gtkmm.h>

class ExampleWindow : public Hildon::Window
{
public:
  ExampleWindow();
  virtual ~ExampleWindow();

private:
  //Signal handlers:
  void on_value_changed();

  //Print function for PickerButton subtitle:
  Glib::ustring picker_button_print_func();

  //Name TreeModelColumns:
  class PeopleColumns : public Gtk::TreeModel::ColumnRecord
  {
  public:
    PeopleColumns()
    {
      add(name_);
      add(surname_);
      add(picture_);
    }

    Gtk::TreeModelColumn<Glib::ustring> name_;
    Gtk::TreeModelColumn<Glib::ustring> surname_;
    Gtk::TreeModelColumn< Glib::RefPtr<Gdk::Pixbuf> > picture_;
  };

  PeopleColumns people_columns_;

  //Child widgets:
  Gtk::HButtonBox box_;
  Hildon::PickerButton pickerbutton_;
  Hildon::TouchSelector touchselector_;
};

#endif /* _MAEMOMM_EXAMPLEWINDOW_H */

File: main.cc

#include <hildonmm.h>
#include "examplewindow.h"
#include <iostream>

int main(int argc, char *argv[])
{
  Gtk::Main kit(argc, argv);
  Hildon::init();

  ExampleWindow window;
  kit.run(window); //Shows the window and returns when it is closed.

  return 0;
}

File: examplewindow.cc

#include "examplewindow.h"
#include <iostream>

static Glib::RefPtr<Gdk::Pixbuf> load_image(const std::string& filename)
{
  Glib::RefPtr<Gdk::Pixbuf> result;

  std::auto_ptr<Glib::Error> ex;
  result = Gdk::Pixbuf::create_from_file("images/" + filename, 
    64, 64, true, ex);
  
  if(ex.get())
  {
    std::cerr << "Error while loading file: " << ex->what() << std::endl;
  }

  return result;
}

ExampleWindow::ExampleWindow() :
  pickerbutton_(Gtk::Hildon::SIZE_HALFSCREEN_WIDTH |
    Gtk::Hildon::SIZE_FINGER_HEIGHT, Hildon::BUTTON_ARRANGEMENT_VERTICAL)
{
  set_title("Hildon::TouchSelector Example");

  // Create TreeModels and add TouchSelectorColumns to show them:
  Glib::RefPtr<Gtk::ListStore> list_store = 
    Gtk::ListStore::create(people_columns_);
  Glib::RefPtr<Hildon::TouchSelectorColumn> name_column =
    touchselector_.append_text_column(list_store);
  name_column->set_property("text-column", 0); // TODO: Add a TextSelectorColumn::set_text_column() method?

  name_column->pack_start(people_columns_.surname_, false);
  name_column->pack_start(people_columns_.picture_);

  // Populate the TreeModel with data:
  Gtk::TreeModel::Row row = *(list_store->append());
  row[people_columns_.name_] = "Armin";
  row[people_columns_.surname_] = "Burgmeier";
  row[people_columns_.picture_] = load_image("armin_burgmeier.png");
  row = *(list_store->append());
  row[people_columns_.name_] = "Daniel";
  row[people_columns_.surname_] = "Borgmann";
  row[people_columns_.picture_] = load_image("daniel_borgmann.png");
  row = *(list_store->append());
  row[people_columns_.name_] = "Daniel";
  row[people_columns_.surname_] = "Elstner";
  row[people_columns_.picture_] = load_image("daniel_elstner.png");
  row = *(list_store->append());
  row[people_columns_.name_] = "David";
  row[people_columns_.surname_] = "King";
  row[people_columns_.picture_] = load_image("david_king.png");
  row = *(list_store->append());
  row[people_columns_.name_] = "Jan Arne";
  row[people_columns_.surname_] = "Petersen";
  row[people_columns_.picture_] = load_image("jan_arne_petersen.png");
  row = *(list_store->append());
  row[people_columns_.name_] = "Mathias";
  row[people_columns_.surname_] = "Hasselmann";
  row[people_columns_.picture_] = load_image("mathias_hasselmann.png");
  row = *(list_store->append());
  row[people_columns_.name_] = "Michael";
  row[people_columns_.surname_] = "Hasselmann";
  row[people_columns_.picture_] = load_image("michael_hasselmann.png");
  row = *(list_store->append());
  row[people_columns_.name_] = "Murray";
  row[people_columns_.surname_] = "Cumming";
  row[people_columns_.picture_] = load_image("murrayc.png");

  
  pickerbutton_.set_selector(touchselector_);
  pickerbutton_.set_title("Select a Name");

  box_.add(pickerbutton_);
  add(box_);

  pickerbutton_.signal_value_changed().connect(
    sigc::mem_fun(*this, &ExampleWindow::on_value_changed));

  //Set a callback function to build a text representation of the 
  //selected item for the picker button:
  touchselector_.set_print_func(
    sigc::mem_fun(*this, &ExampleWindow::picker_button_print_func));

  show_all_children();
}

ExampleWindow::~ExampleWindow()
{
}

void ExampleWindow::on_value_changed()
{
  std::cout << "Selection changed. Current state=" <<
    touchselector_.get_current_text() << std::endl;
}

// Combine strings in TouchSelector, adding space between each string.
Glib::ustring ExampleWindow::picker_button_print_func()
{
  Gtk::TreeModel::iterator iter = touchselector_.get_selected(0);
  Gtk::TreeModel::Row row = *iter;
  Glib::ustring name = row[people_columns_.name_];
  Glib::ustring surname = row[people_columns_.surname_];
  
  return name + " " + surname;
}

Multi-Column TouchSelector Example

This example shows a simple window that contains a Hildon::PickerButton. When clicked, the PickerButton shows a TouchSelector with two independently pannable columns, each showing rows from separate TreeModels.

When a first name and surname are selected, the result appears as the value (sub-title) of the PickerButton and the application sends a line of output to the terminal.

Figure 4.9. Multi-Column TouchSelector

Multi-Column TouchSelector

Source Code

File: examplewindow.h

#ifndef _MAEMOMM_EXAMPLEWINDOW_H
#define _MAEMOMM_EXAMPLEWINDOW_H

#include <hildonmm/window.h>
#include <hildonmm/picker-button.h>
#include <hildonmm/touch-selector.h>
#include <gtkmm.h>

class ExampleWindow : public Hildon::Window
{
public:
  ExampleWindow();
  virtual ~ExampleWindow();

private:
  //Signal handlers:
  void on_value_changed();

  //Print function for PickerButton subtitle:
  Glib::ustring picker_button_print_func();

  //Name TreeModelColumns:
  class NameColumns : public Gtk::TreeModel::ColumnRecord
  {
  public:
    NameColumns()
    {
      add(name_);
    }

    Gtk::TreeModelColumn<Glib::ustring> name_;
  };

  NameColumns name_columns_;

  //Surname TreeModelColumns:
  class SurnameColumns : public Gtk::TreeModel::ColumnRecord
  {
  public:
    SurnameColumns()
    {
      add(surname_);
    }

    Gtk::TreeModelColumn<Glib::ustring> surname_;
  };

  SurnameColumns surname_columns_;

  //Child widgets:
  Gtk::HButtonBox box_;
  Hildon::PickerButton pickerbutton_;
  Hildon::TouchSelector touchselector_;
};

#endif /* _MAEMOMM_EXAMPLEWINDOW_H */

File: main.cc

#include <hildonmm.h>
#include "examplewindow.h"
#include <iostream>

int main(int argc, char *argv[])
{
  Gtk::Main kit(argc, argv);
  Hildon::init();

  ExampleWindow window;
  kit.run(window); //Shows the window and returns when it is closed.

  return 0;
}

File: examplewindow.cc

#include "examplewindow.h"
#include <iostream>

ExampleWindow::ExampleWindow() :
  pickerbutton_(Gtk::Hildon::SIZE_HALFSCREEN_WIDTH |
    Gtk::Hildon::SIZE_FINGER_HEIGHT, Hildon::BUTTON_ARRANGEMENT_VERTICAL)
{
  set_title("Hildon::TouchSelector Example");

  // Create TreeModels and add TouchSelectorColumns to show them:
  Glib::RefPtr<Gtk::ListStore> name_store = 
    Gtk::ListStore::create(name_columns_);
  Glib::RefPtr<Hildon::TouchSelectorColumn> name_column =
    touchselector_.append_text_column(name_store);
  name_column->set_property("text-column", 0); // TODO: Add a TextSelectorColumn::set_text_column() method?

  Glib::RefPtr<Gtk::ListStore> surname_store = 
    Gtk::ListStore::create(surname_columns_);
  Glib::RefPtr<Hildon::TouchSelectorColumn> surname_column =
    touchselector_.append_text_column(surname_store);
  surname_column->set_property("text-column", 0);

  // Populate the name and surname columns.
  Gtk::TreeModel::Row row = *(name_store->append());
  row[name_columns_.name_] = "Alice";
  row = *(name_store->append());
  row[name_columns_.name_] = "Bob";
  row = *(name_store->append());
  row[name_columns_.name_] = "Jane";
  row = *(name_store->append());
  row[name_columns_.name_] = "John";
  row = *(name_store->append());
  row[name_columns_.name_] = "Peter";
  row = *(name_store->append());
  row[name_columns_.name_] = "Sally";
  row = *(name_store->append());
  row[name_columns_.name_] = "Simon";
  row = *(surname_store->append());
  row[surname_columns_.surname_] = "Brown";
  row = *(surname_store->append());
  row[surname_columns_.surname_] = "Jennings";
  row = *(surname_store->append());
  row[surname_columns_.surname_] = "Johnson";
  row = *(surname_store->append());
  row[surname_columns_.surname_] = "King";
  row = *(surname_store->append());
  row[surname_columns_.surname_] = "Matthews";
  row = *(surname_store->append());
  row[surname_columns_.surname_] = "Parker";
  row = *(surname_store->append());
  row[surname_columns_.surname_] = "White";
  
  pickerbutton_.set_selector(touchselector_);
  pickerbutton_.set_title("Select a Name");

  box_.add(pickerbutton_);
  add(box_);

  pickerbutton_.signal_value_changed().connect(
    sigc::mem_fun(*this, &ExampleWindow::on_value_changed));

  //Set a callback function to build a text representation of the 
  //selected item for the picker button:
  touchselector_.set_print_func(
    sigc::mem_fun(*this, &ExampleWindow::picker_button_print_func));

  show_all_children();
}

ExampleWindow::~ExampleWindow()
{
}

void ExampleWindow::on_value_changed()
{
  std::cout << "Selection changed. Current state=" <<
    touchselector_.get_current_text() << std::endl;
}

// Combine strings in TouchSelector, adding space between each string.
Glib::ustring ExampleWindow::picker_button_print_func()
{
  Gtk::TreeModel::iterator iter = touchselector_.get_selected(0);
  Gtk::TreeModel::Row row = *iter;
  Glib::ustring name = row[name_columns_.name_];

  iter = touchselector_.get_selected(1);
  row = *iter;
  Glib::ustring surname = row[surname_columns_.surname_];
  
  return name + " " + surname;
}