/* Stock Item and Icon Browser * * The source code for this demo is only really useful * for the use of Gtk::TreeView, as it demonstrates a few * things not seen in other demos, such as packing multiple * renderers into one column and using Gtk::CellRendererPixbuf * successfully. The code for retrieving and displaying all * stock items probably won't be useful for the vast majority * of applications */ #include <gtkmm.h> class Example_StockBrowser: public Gtk::Window { public: Example_StockBrowser(); virtual ~Example_StockBrowser(); protected: //signal handlers: virtual void on_selection_changed(); virtual Glib::RefPtr<Gtk::TreeModel> create_model(); static Glib::ustring id_to_symbol(const Gtk::StockID& stockid); // convert StockID to Gtk::Stock symbol //Child widgets: Gtk::Frame m_Frame; Gtk::VBox m_VBox; Gtk::HBox m_HBox; Gtk::ScrolledWindow m_ScrolledWindow; Glib::RefPtr<Gtk::TreeModel> m_refTreeModel; Gtk::TreeView m_TreeView; Gtk::Alignment m_Alignment; Glib::RefPtr<Gtk::TreeSelection> m_refTreeSelection; Gtk::Label m_Label_Type; Gtk::Label m_Label_Symbol; Gtk::Label m_Label_ID; Gtk::Label m_Label_Accel; Gtk::Image m_Image; struct ModelColumns : public Gtk::TreeModel::ColumnRecord { Gtk::TreeModelColumn< Glib::RefPtr<Gdk::Pixbuf> > icon; Gtk::TreeModelColumn<Glib::ustring> symbol; Gtk::TreeModelColumn<Glib::ustring> label; Gtk::TreeModelColumn<Glib::ustring> accel; Gtk::TreeModelColumn<Gtk::StockID> id; ModelColumns() { add(icon); add(symbol); add(label); add(accel); add(id); } }; const ModelColumns m_columns; }; Gtk::Window* do_stock_browser() { return new Example_StockBrowser(); } Example_StockBrowser::Example_StockBrowser() : m_Frame("Selected Item"), m_VBox(false, 8), m_HBox(false, 8), m_Alignment(Gtk::ALIGN_CENTER, Gtk::ALIGN_START, 0.0, 0.0) { set_title("Stock Icons and Items"); set_default_size(-1, 500); set_border_width(8); add(m_HBox); m_ScrolledWindow.set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); m_HBox.pack_start(m_ScrolledWindow, Gtk::PACK_SHRINK); // create the TreeModel with all the stock item data in it m_refTreeModel = create_model(); // create the TreeView, associate the TreeModel with it m_TreeView .set_model(m_refTreeModel); m_ScrolledWindow.add(m_TreeView); // add columns to the TreeView, mapping model Columns to TreeView m_columns:: { //The pixbuf/text column: Gtk::TreeView::Column* pColumn = Gtk::manage( new Gtk::TreeView::Column("Symbol") ); //We specify the renderer(s) after construction. // The icon/symbol column uses two CellRenderers: Here we see why Gtk::TreeView is so good // m_columns.icon and m_columns.symbol are columns in the model. pColumn is the column in the TreeView: pColumn->pack_start(m_columns.icon, false); pColumn->pack_start(m_columns.symbol); m_TreeView.append_column(*pColumn); } // the label column m_TreeView.append_column("Label", m_columns.label); //Defaults to CellRendererText for a string model column. // the accelerator column m_TreeView.append_column("Accelerator", m_columns.accel); //Defaults to CellRendererText for a string model column. // the ID column m_TreeView.append_column("ID", m_columns.id); //Defaults to CellRendererText for a string model column. m_HBox.pack_end(m_Alignment); m_Alignment.add(m_Frame); m_VBox.set_border_width(4); m_Frame.add(m_VBox); m_VBox.pack_start(m_Label_Type, Gtk::PACK_SHRINK); m_VBox.pack_start(m_Image, Gtk::PACK_SHRINK); m_VBox.pack_start(m_Label_Accel, Gtk::PACK_SHRINK); m_VBox.pack_start(m_Label_Symbol, Gtk::PACK_SHRINK); m_VBox.pack_start(m_Label_ID, Gtk::PACK_SHRINK); m_refTreeSelection = m_TreeView.get_selection(); m_refTreeSelection->set_mode(Gtk::SELECTION_SINGLE); m_refTreeSelection->signal_changed().connect( sigc::mem_fun(*this, &Example_StockBrowser::on_selection_changed)); show_all(); } Example_StockBrowser::~Example_StockBrowser() { } Glib::RefPtr<Gtk::TreeModel> Example_StockBrowser::create_model() { Glib::RefPtr<Gtk::ListStore> refStore = Gtk::ListStore::create(m_columns); refStore->set_sort_column(m_columns.id, Gtk::SORT_ASCENDING); // obtain the ids of all stock items typedef std::vector<Gtk::StockID> type_vecIDs; type_vecIDs vecIDs = Gtk::Stock::get_ids(); // iterate through them, populating the ListStore as appropriate for(type_vecIDs::const_iterator iterIDs = vecIDs.begin(); iterIDs != vecIDs.end(); ++iterIDs) { const Gtk::StockID& stockid = *iterIDs; // Add a new empty row to the ListStore: Gtk::TreeModel::Row row = *(refStore->append()); // Populate ID and symbol columns: row[m_columns.id] = stockid; row[m_columns.symbol] = id_to_symbol(stockid); // get a Gtk::StockItem object for use: Gtk::StockItem item; if(Gtk::Stock::lookup(stockid, item)) { // Populate Accel column, if the stock item has an accelerator key. if(const unsigned int keyval = item.get_keyval()) row[m_columns.accel] = Gtk::AccelGroup::name(keyval, item.get_modifier()); row[m_columns.label] = item.get_label(); } // Populate icon column: row[m_columns.icon] = render_icon(stockid, Gtk::ICON_SIZE_MENU); } return refStore; } /* gtk-foo-bar -> Gtk::Stock::FOO_BAR */ Glib::ustring Example_StockBrowser::id_to_symbol(const Gtk::StockID& stockid) { static const char prefix[] = "gtk-"; const size_t prefix_length = sizeof(prefix) - 1; const Glib::ustring id = stockid.get_string(); Glib::ustring::const_iterator id_pos = id.begin(); Glib::ustring scope; if((id.length() >= prefix_length) && (id.compare(0, prefix_length, prefix) == 0)) { scope = "Gtk::Stock::"; // This does not work with the SUN Forte compiler: // "/opt/SUNWspro/WS6U2/include/CC/Cstd/rw/iterator", // line 331: Error: Could not find a match for // std::__iterator_category<std::T>(Glib::ustring_Iterator<const char*>). // "example_stockbrowser.cc", line 186: Where: While instantiating // "std::advance<Glib::ustring_Iterator<const char*>, unsigned>(Glib::ustring_Iterator<const char*>&, unsigned)". // "example_stockbrowser.cc", line 186: Where: Instantiated from non-template code. // // std::advance(id_pos, prefix_length); // // So we do this instead: for(Glib::ustring::size_type i = 0; i < prefix_length; ++i) ++id_pos; } Glib::ustring symbol; std::replace_copy(id_pos, id.end(), std::back_inserter(symbol), gunichar('-'), gunichar('_')); return scope + symbol.uppercase(); } // triggered when TreeView selection changes void Example_StockBrowser::on_selection_changed() { // put all the nice data stuff in the box on the right // Access the model "row" corresponding to the selected TreeView "row". if(const Gtk::TreeModel::iterator iter = m_refTreeSelection->get_selected()) { const Gtk::TreeModel::Row row = *iter; // get the data out of the model const Gtk::StockID stockid = row[m_columns.id]; const Glib::ustring symbol = row[m_columns.symbol]; const Glib::ustring accel = row[m_columns.accel]; const Glib::ustring label = row[m_columns.label]; const Glib::RefPtr<Gdk::Pixbuf> icon = row[m_columns.icon]; // Show what data was available: const char* type_text = "???????"; if(!label.empty() && icon) type_text = "Icon and Item"; else if(icon) type_text = "Icon Only"; else if(!label.empty()) type_text = "Item Only"; m_Label_Type.set_text(type_text); m_Label_Symbol.set_text(symbol); m_Label_ID.set_text(stockid.get_string()); m_Label_Accel.set_text_with_mnemonic(label + ' ' + accel); if(icon) //If there's a stock icon: { // find the largest size the icon comes in: const Gtk::IconSet iconset = Gtk::IconSet::lookup_default(stockid); typedef std::vector<Gtk::IconSize> type_vecSizes; type_vecSizes sizes = iconset.get_sizes(); Gtk::IconSize best_size = Gtk::ICON_SIZE_INVALID; int biggest_pixelcount = 0; for(type_vecSizes::const_iterator psize = sizes.begin(); psize != sizes.end(); ++psize) { int width = 0; int height = 0; Gtk::IconSize::lookup(*psize, width, height); if(width * height > biggest_pixelcount) { biggest_pixelcount = width * height; best_size = *psize; } } m_Image.set(stockid, best_size); } else { m_Image.clear(); } } else { m_Label_Type.set_text("No selected item"); m_Label_Symbol.set_text(""); m_Label_ID.set_text(""); m_Label_Accel.set_text(""); m_Image.clear(); } }