diff options
Diffstat (limited to 'app/wlib/gtklib/treeview.c')
-rw-r--r-- | app/wlib/gtklib/treeview.c | 530 |
1 files changed, 530 insertions, 0 deletions
diff --git a/app/wlib/gtklib/treeview.c b/app/wlib/gtklib/treeview.c new file mode 100644 index 0000000..e2f2259 --- /dev/null +++ b/app/wlib/gtklib/treeview.c @@ -0,0 +1,530 @@ +/** \file treeview.c + * Basic treeview functionality for dropbox and listbox + */ + +/* XTrkCad - Model Railroad CAD + * + * Copyright 2016 Martin Fischer <m_fischer@users.sf.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#define GTK_DISABLE_SINGLE_INCLUDES +#define GDK_DISABLE_DEPRECATED +#define GTK_DISABLE_DEPRECATED +#define GSEAL_ENABLE + +#include <glib-object.h> +#include <gtk/gtk.h> +#include <gdk/gdk.h> + +#include "gtkint.h" +//#include "i18n.h" + +#define ROW_HEIGHT (15) + +/** + * Get the count of columns in list + * + * \param b IN widget + * \returns count row + */ + +int +wTreeViewGetCount(wList_p b) +{ + return b->count; +} + +/** + * Clear the list + * + * \param b IN widget + */ + +void +wTreeViewClear(wList_p b) +{ + assert(b != NULL); + + wlibListStoreClear(b->listStore); +} + +/** + * Get the user data for a list element + * + * \param b IN widget + * \param inx IN row + * \returns the user data for the specified row + */ + +void * +wTreeViewGetItemContext(wList_p b, int row) +{ + wListItem_p id_p; + + id_p = wlibListItemGet(b->listStore, row, NULL); + + if (id_p) { + return id_p->itemData; + } else { + return NULL; + } +} + +/** + * Returns the current selected list entry. + * If <val> if '-1' then no entry is selected. + * + * \param b IN widget + * \returns row of selected entry or -1 if none is selected + */ + +wIndex_t wListGetIndex( + wList_p b) +{ + assert(b!=NULL); + + return b->last; +} + +/** + * Set an entry in the list to selected. + * + * \param b IN widget + * \param index IN entry if -1 the current selection is cleared + * + */ + +void +wlibTreeViewSetSelected(wList_p b, int index) +{ + GtkTreeSelection *sel; + GtkTreeIter iter; + + wListItem_p id_p; + + sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(b->treeView)); + + if (gtk_tree_selection_count_selected_rows(sel)) { + int inx; + + gtk_tree_selection_unselect_all(sel); + + // and synchronize the internal data structures + wTreeViewGetCount(b); + + for (inx=0; inx<b->count; inx++) { + id_p = wlibListItemGet(b->listStore, inx, NULL); + id_p->selected = FALSE; + } + } + + if (index != -1) { + gint childs; + + childs = gtk_tree_model_iter_n_children (GTK_TREE_MODEL(b->listStore), + NULL ); + + if(index < childs) { + gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(b->listStore), + &iter, + NULL, + index); + gtk_tree_selection_select_iter(sel, + &iter); + + id_p = wlibListItemGet(b->listStore, index, NULL); + + if (id_p) { + id_p->selected = TRUE; + } + } + } +} + +/** + * Create a new tree view for a list store. Titles are enabled optionally. + * + * \param ls IN list store + * \param showTitles IN add column titles + * \param multiSelection IN enable selecting multiple rows + * \returns + */ + +GtkWidget * +wlibNewTreeView(GtkListStore *ls, int showTitles, int multiSelection) +{ + GtkWidget *treeView; + GtkTreeSelection *sel; + assert(ls != NULL); + + /* create and configure the tree view */ + treeView = gtk_tree_view_new_with_model(GTK_TREE_MODEL(ls)); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeView), showTitles); + + /* set up selection handling */ + sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeView)); + gtk_tree_selection_set_mode(sel, + (multiSelection)?GTK_SELECTION_MULTIPLE:GTK_SELECTION_BROWSE); + + return (treeView); +} + + +static int changeListColumnWidth( + GtkTreeViewColumn * column, + void * width) +{ + //wList_p bl = (wList_p)data; + + //if (bl->recursion) + //return 0; + //if ( col >= 0 && col < bl->colCnt ) + //bl->colWidths[col] = width; + return 0; +} + +/** + * Create and initialize a column in treeview. Initially all columns are + * invisible. Visibility is set when values are added to the specific + * column + * + * \param tv IN treeview + * \param renderer IN renderer to use + * \param attribute IN attribute for column + * \param value IN value to set + */ + +static void +wlibAddColumn(GtkWidget *tv, int visibility, GtkCellRenderer *renderer, + char *attribute, int value) +{ + GtkTreeViewColumn *column; + + column = gtk_tree_view_column_new(); + gtk_tree_view_column_pack_start(column, + renderer, + TRUE); + gtk_tree_view_column_add_attribute(column, renderer, attribute, value); + gtk_tree_view_column_set_visible(column, visibility); + gtk_tree_view_column_set_resizable(column, TRUE); + + gtk_tree_view_append_column(GTK_TREE_VIEW(tv), column); + +// g_signal_connect( column, "notify::width", G_CALLBACK(changeListColumnWidth), tv ); +} + +/** + * Add a number of columns to the text view. This includes the bitmap + * columns and a given number of text columns. + * + * \param tv IN tree view + * \param count IN number of text columns + * \returns number of columns + */ + +int +wlibTreeViewAddColumns(GtkWidget *tv, int count) +{ + GtkCellRenderer *renderer; + int i; + + assert(tv != NULL); + renderer = gtk_cell_renderer_pixbuf_new(); + /* first visible column is used for bitmaps */ + wlibAddColumn(tv, FALSE, renderer, "pixbuf", LISTCOL_BITMAP); + + renderer = gtk_cell_renderer_text_new(); + + /* add renderers to all columns */ + for (i = 0; i < count; i++) { + wlibAddColumn(tv, TRUE, renderer, "text", i + LISTCOL_TEXT); + } + + return i; +} + +/** + * Add the titles to all columns in a tree view. + * + * \param tv IN treeview + * \param titles IN titles + * \returns number of titles set + */ + +int +wlibAddColumnTitles(GtkWidget *tv, const char **titles) +{ + int i = 0; + + assert(tv != NULL); + + if (titles) { + while (*titles) { + GtkTreeViewColumn *column; + + column = gtk_tree_view_get_column(GTK_TREE_VIEW(tv), i + 1); + + if (column) { + gtk_tree_view_column_set_title(column, titles[ i ]); + i++; + } else { + break; + } + } + } + + return i; +} + +/** + * Add text to the text columns of the tree view and update the context + * information + * + * \param tv IN treeview + * \param cols IN number of cols to change + * \param label IN tab separated string of values + * \param userData IN additional context information + * \returns + */ + +int +wlibTreeViewAddData(GtkWidget *tv, int cols, char *label, GdkPixbuf *pixbuf, + wListItem_p userData) +{ + GtkListStore *listStore = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW( + tv))); + + wlibListStoreAddData(listStore, pixbuf, cols, userData); + + if (pixbuf) { + GtkTreeViewColumn *column; + + // first column in list store has pixbuf + column = gtk_tree_view_get_column(GTK_TREE_VIEW(tv), 0); + gtk_tree_view_column_set_visible(column, + TRUE); + } + +} + +/** + * Add a row to the tree view. As necessary the adjustment is update in + * order to make sure, that the list box is fully visible or has a + * scrollbar. + * + * \param b IN the list box + * \param label IN the text labels + * \param bm IN bitmap to show at start + * \param id_p IN user data + */ + +void +wlibTreeViewAddRow(wList_p b, char *label, wIcon_p bm, wListItem_p id_p) +{ + GtkAdjustment *adj; + GdkPixbuf *pixbuf = NULL; + + if (bm) { + pixbuf = wlibMakePixbuf(bm); + } + + wlibTreeViewAddData(b->treeView, b->colCnt, (char *)label, pixbuf, id_p); + + adj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(b->widget)); + + if (gtk_adjustment_get_upper(adj) < gtk_adjustment_get_step_increment(adj) * + (b->count+1)) { + gtk_adjustment_set_upper(adj, + gtk_adjustment_get_upper(adj) + + gtk_adjustment_get_step_increment(adj)); + gtk_adjustment_changed(adj); + } + + b->last = gtk_tree_model_iter_n_children(gtk_tree_view_get_model(GTK_TREE_VIEW( + b->treeView)), + NULL); + +} + +/** + * Function for handling a selection change. The internal data structure + * for the changed row is updated. If a handler function for the list + * is given, the data for the row are retrieved and passed to that + * function. This is used to update other fields in a dialog (see Price + * List for an example). + * + * \param selection IN current selection + * \param model IN + * \param path IN + * \param path_currently_selected IN + * \param data IN the list widget + */ + +gboolean +changeSelection(GtkTreeSelection *selection, + GtkTreeModel *model, + GtkTreePath *path, + gboolean path_currently_selected, + gpointer data) +{ + GtkTreeIter iter; + GValue value = { 0 }; + wListItem_p id_p = NULL; + wList_p bl = (wList_p)data; + int row; + char *text; + + text = gtk_tree_path_to_string(path); + row = atoi(text); + g_free(text); + + gtk_tree_model_get_iter(model, &iter, path); + gtk_tree_model_get_value(model, &iter, LISTCOL_DATA, &value); + + id_p = g_value_get_pointer(&value); + id_p->selected = !path_currently_selected; + + if (id_p->selected) { + bl->last = row; + + if (bl->valueP) { + *bl->valueP = row; + } + + if (bl->action) { + bl->action(row, id_p->label, 1, bl->data, id_p->itemData); + } + } + + return TRUE; +} + +/** + * Create a multi column list box. + * + * \param parent IN parent window + * \param x IN X-position + * \param y IN Y-position + * \param helpStr IN Help string + * \param labelStr IN Label + * \param option IN Options + * \param number IN Number of displayed entries + * \param width IN Width of list + * \param colCnt IN Number of columns + * \param colWidths IN Width of columns + * \param colRightJust IN justification of columns + * \param colTitles IN array of titles for columns + * \param valueP IN Selected index + * \param action IN Callback + * \param data IN Context + * \returns created list box + */ + +wList_p wListCreate( + wWin_p parent, + wPos_t x, + wPos_t y, + const char * helpStr, + const char * labelStr, + long option, + long number, + wPos_t width, + int colCnt, + wPos_t * colWidths, + wBool_t * colRightJust, + const char ** colTitles, + long *valueP, + wListCallBack_p action, + void *data) +{ + GtkTreeSelection *sel; + wList_p bl; + static wPos_t zeroPos = 0; + + assert(width != 0); + + bl = (wList_p)wlibAlloc(parent, B_LIST, x, y, labelStr, sizeof *bl, data); + bl->option = option; + bl->number = number; + bl->count = 0; + bl->last = -1; + bl->valueP = valueP; + bl->action = action; + bl->listX = bl->realX; + + if (colCnt <= 0) { + colCnt = 1; + colWidths = &zeroPos; + } + + bl->colCnt = colCnt; + bl->colWidths = (wPos_t*)malloc(colCnt * sizeof *(wPos_t*)0); + memcpy(bl->colWidths, colWidths, colCnt * sizeof *(wPos_t*)0); + + /* create the data structure for data */ + bl->listStore = wlibNewListStore(colCnt); + /* create the widget for the list store */ + bl->treeView = wlibNewTreeView(bl->listStore, + colTitles != NULL, + option & BL_MANY); + + + sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(bl->treeView)); + + gtk_tree_selection_set_select_function(sel, + changeSelection, + bl, + NULL); + + wlibTreeViewAddColumns(bl->treeView, colCnt); + + wlibAddColumnTitles(bl->treeView, colTitles); + + wlibComputePos((wControl_p)bl); + + bl->widget = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(bl->widget), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(bl->widget), + bl->treeView); + + gtk_widget_set_size_request(bl->widget, width, (number+1)*ROW_HEIGHT); + +/// g_signal_connect( GTK_OBJECT(bl->list), "resize_column", G_CALLBACK(changeListColumnWidth), bl ); + + gtk_widget_show_all(bl->widget); + + gtk_fixed_put(GTK_FIXED(parent->widget), bl->widget, bl->realX, bl->realY); + wlibControlGetSize((wControl_p)bl); + + if (labelStr) { + bl->labelW = wlibAddLabel((wControl_p)bl, labelStr); + } + + wlibAddButton((wControl_p)bl); + wlibAddHelpString(bl->widget, helpStr); + + return bl; +} |