/** \file list.c * Listboxes, dropdown boxes, combo boxes */ /* XTrkCad - Model Railroad CAD * Copyright (C) 2005 Dave Bullis * * 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 #include #include #include #define GTK_DISABLE_SINGLE_INCLUDES #define GDK_DISABLE_DEPRECATED #define GTK_DISABLE_DEPRECATED #define GSEAL_ENABLE #include #include #include #include "wlib.h" #include "gtkint.h" #include "i18n.h" struct listSearch { const char *search; char *result; int row; }; /* ***************************************************************************** * * List Boxes * ***************************************************************************** */ /** * Remove all entries from the list * * \param b IN list * \return */ void wListClear( wList_p b) { assert(b!= NULL); b->recursion++; if (b->type == B_DROPLIST) { wDropListClear(b); } else { wTreeViewClear(b); } b->recursion--; b->last = -1; b->count = 0; } /** * Makes the th entry (0-origin) the current selection. * If if '-1' then no entry is selected. * \param b IN List * \param element IN Index */ void wListSetIndex( wList_p b, int element) { if (b->widget == 0) { abort(); } b->recursion++; if (b->type == B_DROPLIST) { wDropListSetIndex(b, element); } else { wlibTreeViewSetSelected(b, element); } b->last = element; b->recursion--; } /** * CompareListData is called when a list is searched for a specific * data entry. It is called in sequence and does a string compare * between the label of the current row and the search argument. If * identical the label is placed in the search argument. * It is a GTK foreach() function. * * \param model IN searched model * \param path IN unused * \param iter IN current iterator * \param data IN/OUT pointer to data structure with search criteria * \return TRUE if identical, FALSE otherwise */ int CompareListData(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) { wListItem_p id_p; struct listSearch *search = (struct listSearch *)data; gtk_tree_model_get(model, iter, LISTCOL_DATA, &id_p, -1); if (id_p && id_p->label && !strcmp(id_p->label, search->search)) { search->result = (char *)id_p->label; return TRUE; } else { search->result = NULL; search->row++; return FALSE; } } /** * Find the row which contains the specified text. * * \param b IN * \param val IN * \returns found row or -1 if not found */ wIndex_t wListFindValue( wList_p b, const char * val) { struct listSearch thisSearch; assert(b!=NULL); assert(b->listStore!=NULL); thisSearch.search = val; thisSearch.row = 0; gtk_tree_model_foreach(GTK_TREE_MODEL(b->listStore), CompareListData, (void *)&thisSearch); if (!thisSearch.result) { return -1; } else { return thisSearch.row; } } /** * Return the number of rows in the list * * \param b IN widget * \returns number of rows */ wIndex_t wListGetCount( wList_p b) { if (b->type == B_DROPLIST) { return wDropListGetCount(b); } else { return wTreeViewGetCount(b); } } /** * 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 * wListGetItemContext( wList_p b, wIndex_t inx) { if (inx < 0) { return NULL; } if (b->type == B_DROPLIST) { return wDropListGetItemContext(b, inx); } else { return wTreeViewGetItemContext(b, inx); } } /** * * \param bl IN widget * \param labelStr IN ? * \param labelSize IN ? * \param listDataRet IN * \param itemDataRet IN * \returns */ wIndex_t wListGetValues( wList_p bl, char * labelStr, int labelSize, void * * listDataRet, void * * itemDataRet) { wListItem_p id_p; wIndex_t inx = bl->last; const char * entry_value = ""; void * item_data = NULL; assert(bl != NULL); assert(bl->listStore != NULL); if (bl->type == B_DROPLIST && bl->editted) { entry_value = gtk_entry_get_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN( bl->widget)))); item_data = NULL; inx = bl->last = -1; } else { //Make sure in range if (bl->last > bl->count-1) { bl->last = bl->count-1; } inx = bl->last; if (inx >= 0) { id_p = wlibListStoreGetContext(bl->listStore, inx); if (id_p==NULL) { fprintf(stderr, "wListGetValues - id_p == NULL\n"); bl->last = -1; } else { entry_value = id_p->label; item_data = id_p->itemData; } } } if (labelStr) { strncpy(labelStr, entry_value, labelSize); } if (listDataRet) { *listDataRet = bl->data; } if (itemDataRet) { *itemDataRet = item_data; } return bl->last; } /** * Check whether row is selected * \param b IN widget * \param inx IN row * \returns TRUE if selected, FALSE if not existant or unselected */ wBool_t wListGetItemSelected( wList_p b, wIndex_t inx) { wListItem_p id_p; if (inx < 0) { return FALSE; } id_p = wlibListStoreGetContext(b->listStore, inx); if (id_p) { return id_p->selected; } else { return FALSE; } } /** * Count the number of selected rows in list * * \param b IN widget * \returns count of selected rows */ wIndex_t wListGetSelectedCount( wList_p b) { wIndex_t selcnt, inx; for (selcnt=inx=0; inxcount; inx++) if (wListGetItemSelected(b, inx)) { selcnt++; } return selcnt; } /** * Select all items in list. * * \param bl IN list handle * \return */ void wListSelectAll(wList_p bl) { wIndex_t inx; GtkTreeSelection *selection; assert(bl != NULL); // mark all items selected selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(bl->treeView)); gtk_tree_selection_select_all(selection); // and synchronize the internal data structures wListGetCount(bl); for (inx=0; inxcount; inx++) { wListItem_p ldp; ldp = wlibListStoreGetContext(bl->listStore, inx); if (ldp) { ldp->selected = TRUE; } } } /** * Set the value for a row in the listbox * * \param b IN widget * \param row IN row to change * \param labelStr IN string with new tab separated values * \param bm IN icon * \param itemData IN data for row * \returns TRUE */ wBool_t wListSetValues( wList_p b, wIndex_t row, const char * labelStr, wIcon_p bm, void *itemData) { assert(b->listStore != NULL); b->recursion++; if (b->type == B_DROPLIST) { wDropListSetValues(b, row, labelStr, bm, itemData); } else { wlibListStoreUpdateValues(b->listStore, row, b->colCnt, (char *)labelStr, bm); } b->recursion--; return TRUE; } /** * Remove a line from the list * \param b IN widget * \param inx IN row */ void wListDelete( wList_p b, wIndex_t inx) { GtkTreeIter iter; assert(b->listStore != 0); assert(b->type != B_DROPLIST); b->recursion++; if (b->type == B_DROPLIST) { wNotice("Deleting from dropboxes is not implemented!", "Continue", NULL); } else { gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(b->listStore), &iter, NULL, inx); gtk_list_store_remove(b->listStore, &iter); b->count--; } if (b->last == inx-1) { b->last = -1; } else if (b->last >= inx) { b->last = -1; } b->recursion--; return; } /** * Get the widths of the columns * * \param bl IN widget * \param colCnt IN number of columns * \param colWidths OUT array for widths * \returns */ int wListGetColumnWidths( wList_p bl, int colCnt, wWinPix_t * colWidths) { int inx; if (bl->type != B_LIST) { return 0; } if (bl->colWidths == NULL) { return 0; } for (inx=0; inxcolCnt) { colWidths[inx] = bl->colWidths[inx]; } else { colWidths[inx] = 0; } } return bl->colCnt; } /** * Adds a entry to the list with name . * * \param b IN widget * \param labelStr IN Entry name * \param bm IN Entry bitmap * \param itemData IN User context * \returns */ wIndex_t wListAddValue( wList_p b, const char * labelStr, wIcon_p bm, void * itemData) { wListItem_p id_p; assert(b != NULL); b->recursion++; id_p = (wListItem_p)g_malloc(sizeof *id_p); memset(id_p, 0, sizeof *id_p); id_p->itemData = itemData; id_p->active = TRUE; if (labelStr == NULL) { labelStr = ""; } id_p->label = strdup(labelStr); id_p->listP = b; if (b->type == B_DROPLIST) { wDropListAddValue(b, (char *)labelStr, id_p); } else { wlibTreeViewAddRow(b, (char *)labelStr, bm, id_p); } //free(id_p->label); b->count++; b->recursion--; if (b->count == 1) { b->last = 0; } return b->count-1; } /** * Set the size of the list * * \param bl IN widget * \param w IN width * \param h IN height (ignored for droplist) */ void wListSetSize(wList_p bl, wWinPix_t w, wWinPix_t h) { if (bl->type == B_DROPLIST) { gtk_widget_set_size_request(bl->widget, w, -1); } else { gtk_widget_set_size_request(bl->widget, w, h); } bl->w = w; bl->h = h; } /** * Create a single column list box (not what the names suggests!) * \todo Improve or discard totally, in this case, remove from param.c \ * as well. * * \param varname1 IN this is a variable * \param varname2 OUT and another one that is modified * \return describe the return value */ wList_p wComboListCreate( wWin_p parent, /* Parent window */ wWinPix_t x, /* X-position */ wWinPix_t y, /* Y-position */ const char * helpStr, /* Help string */ const char * labelStr, /* Label */ long option, /* Options */ long number, /* Number of displayed list entries */ wWinPix_t width, /* Width */ long *valueP, /* Selected index */ wListCallBack_p action, /* Callback */ void *data) /* Context */ { wNotice("ComboLists are not implemented!", "Abort", NULL); abort(); }