#if defined(Hiro_IconView) namespace hiro { static auto IconView_activate(GtkIconView* iconView, GtkTreePath* path, pIconView* p) -> void { if(!p->locked()) p->self().doActivate(); } static auto IconView_buttonEvent(GtkTreeView* treeView, GdkEventButton* event, pIconView* p) -> signed { if(event->type == GDK_BUTTON_RELEASE && event->button == 3) { if(!p->locked()) p->self().doContext(); return false; } return false; } static auto IconView_change(GtkIconView* iconView, pIconView* p) -> void { p->_updateSelected(); } auto pIconView::construct() -> void { gtkWidget = gtk_scrolled_window_new(0, 0); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(gtkWidget), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(gtkWidget), GTK_SHADOW_ETCHED_IN); store = gtk_list_store_new(2, GDK_TYPE_PIXBUF, G_TYPE_STRING); subWidget = gtk_icon_view_new_with_model(GTK_TREE_MODEL(store)); gtk_icon_view_set_pixbuf_column(GTK_ICON_VIEW(subWidget), 0); gtk_icon_view_set_text_column(GTK_ICON_VIEW(subWidget), 1); gtk_icon_view_set_reorderable(GTK_ICON_VIEW(subWidget), false); gtk_icon_view_set_margin(GTK_ICON_VIEW(subWidget), 0); gtk_icon_view_set_spacing(GTK_ICON_VIEW(subWidget), 0); gtk_icon_view_set_column_spacing(GTK_ICON_VIEW(subWidget), 0); gtk_icon_view_set_row_spacing(GTK_ICON_VIEW(subWidget), 0); gtk_icon_view_set_item_padding(GTK_ICON_VIEW(subWidget), 0); gtk_container_add(GTK_CONTAINER(gtkWidget), subWidget); gtk_widget_show(subWidget); setBackgroundColor(state().backgroundColor); setBatchable(state().batchable); setFlow(state().flow); setForegroundColor(state().foregroundColor); setOrientation(state().orientation); for(auto position : range(self().items())) { auto& item = state().items[position]; append(item); } _updateSelected(); g_signal_connect(G_OBJECT(subWidget), "button-press-event", G_CALLBACK(IconView_buttonEvent), (gpointer)this); g_signal_connect(G_OBJECT(subWidget), "button-release-event", G_CALLBACK(IconView_buttonEvent), (gpointer)this); g_signal_connect(G_OBJECT(subWidget), "item-activated", G_CALLBACK(IconView_activate), (gpointer)this); g_signal_connect(G_OBJECT(subWidget), "selection-changed", G_CALLBACK(IconView_change), (gpointer)this); pWidget::construct(); } auto pIconView::destruct() -> void { gtk_widget_destroy(subWidget); gtk_widget_destroy(gtkWidget); } auto pIconView::append(sIconViewItem item) -> void { GtkTreeIter iter; gtk_list_store_append(store, &iter); setItemIcon(item->offset(), item->state.icon); setItemSelected(item->offset(), item->state.selected); setItemText(item->offset(), item->state.text); } auto pIconView::remove(sIconViewItem item) -> void { lock(); GtkTreeIter iter; if(gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(store), &iter, string{item->offset()})) { gtk_list_store_remove(store, &iter); } _updateSelected(); unlock(); } auto pIconView::reset() -> void { lock(); gtk_list_store_clear(store); _updateSelected(); unlock(); } auto pIconView::setBackgroundColor(Color color) -> void { GdkColor gdkColor = CreateColor(color); gtk_widget_modify_base(subWidget, GTK_STATE_NORMAL, color ? &gdkColor : nullptr); } auto pIconView::setBatchable(bool batchable) -> void { gtk_icon_view_set_selection_mode(GTK_ICON_VIEW(subWidget), batchable ? GTK_SELECTION_MULTIPLE : GTK_SELECTION_SINGLE ); } auto pIconView::setFlow(Orientation flow) -> void { //GTK+ does not support vertical flow ... the closest we can get is a horizontal flow with only one column if(flow == Orientation::Horizontal) { gtk_icon_view_set_columns(GTK_ICON_VIEW(subWidget), -1); gtk_icon_view_set_item_width(GTK_ICON_VIEW(subWidget), -1); } else { gtk_icon_view_set_columns(GTK_ICON_VIEW(subWidget), 1); gtk_icon_view_set_item_width(GTK_ICON_VIEW(subWidget), max(128, pSizable::state().geometry.width() - 64)); } } auto pIconView::setForegroundColor(Color color) -> void { GdkColor gdkColor = CreateColor(color); gtk_widget_modify_text(subWidget, GTK_STATE_NORMAL, color ? &gdkColor : nullptr); } auto pIconView::setGeometry(Geometry geometry) -> void { pWidget::setGeometry(geometry); if(state().flow == Orientation::Vertical) { gtk_icon_view_set_item_width(GTK_ICON_VIEW(subWidget), max(128, pSizable::state().geometry.width() - 64)); } } auto pIconView::setItemIcon(unsigned position, const image& icon) -> void { if(position >= self().itemCount()) return; GtkTreeIter iter; if(gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(store), &iter, string{position})) { if(icon) { GdkPixbuf* pixbuf = CreatePixbuf(icon); gtk_list_store_set(store, &iter, 0, pixbuf, -1); } else { gtk_list_store_set(store, &iter, 0, nullptr, -1); } } } auto pIconView::setItemSelected(unsigned position, bool selected) -> void { if(position >= self().itemCount()) return; lock(); GtkTreePath* path = gtk_tree_path_new_from_string(string{position}); if(selected) { gtk_icon_view_select_path(GTK_ICON_VIEW(subWidget), path); } else { gtk_icon_view_unselect_path(GTK_ICON_VIEW(subWidget), path); } gtk_tree_path_free(path); _updateSelected(); unlock(); } auto pIconView::setItemSelected(const vector& selections) -> void { lock(); setItemSelectedNone(); for(auto& position : selections) setItemSelected(position, true); _updateSelected(); unlock(); } auto pIconView::setItemSelectedAll() -> void { lock(); gtk_icon_view_select_all(GTK_ICON_VIEW(subWidget)); _updateSelected(); unlock(); } auto pIconView::setItemSelectedNone() -> void { lock(); gtk_icon_view_unselect_all(GTK_ICON_VIEW(subWidget)); _updateSelected(); unlock(); } auto pIconView::setItemText(unsigned position, const string& text) -> void { if(position >= self().itemCount()) return; GtkTreeIter iter; if(gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(store), &iter, string{position})) { gtk_list_store_set(store, &iter, 1, (const char*)text, -1); } } auto pIconView::setOrientation(Orientation orientation) -> void { gtk_icon_view_set_item_orientation(GTK_ICON_VIEW(subWidget), orientation == Orientation::Horizontal ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL ); } auto pIconView::_updateSelected() -> void { vector selected; GList* list = gtk_icon_view_get_selected_items(GTK_ICON_VIEW(subWidget)); GList* p = list; while(p) { auto path = (GtkTreePath*)p->data; char* pathString = gtk_tree_path_to_string(path); unsigned position = toNatural(pathString); g_free(pathString); selected.append(position); p = p->next; } g_list_foreach(list, (GFunc)gtk_tree_path_free, nullptr); g_list_free(list); bool identical = selected.size() == currentSelection.size(); if(identical) { for(unsigned n = 0; n < selected.size(); n++) { if(selected[n] != currentSelection[n]) { identical = false; break; } } } if(identical) return; currentSelection = selected; for(auto& item : state().items) item->state.selected = false; for(auto& position : currentSelection) { if(position >= self().itemCount()) continue; state().items[position]->state.selected = true; } if(!locked()) self().doChange(); } } #endif