tUse GtkTreeView for inventory lists - vaccinewars - be a doctor and try to vaccinate the world
(HTM) git clone git://src.adamsgaard.dk/vaccinewars
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) LICENSE
---
(DIR) commit 3300611f43cf08cdee8ff35240631c072f39674b
(DIR) parent ff75c12c4ffe68e12f48110b05dcb6537ab923eb
(HTM) Author: Ben Webb <ben@salilab.org>
Date: Sat, 21 Nov 2020 23:21:07 -0800
Use GtkTreeView for inventory lists
Replace our use of GtkCList for inventory (drugs or
guns carried, or available for purchase).
Diffstat:
M src/gui_client/gtk_client.c | 247 ++++++++++++++++---------------
1 file changed, 131 insertions(+), 116 deletions(-)
---
(DIR) diff --git a/src/gui_client/gtk_client.c b/src/gui_client/gtk_client.c
t@@ -592,7 +592,6 @@ void HandleClientMessage(char *pt, Player *Play)
break;
case C_DRUGHERE:
UpdateInventory(&ClientData.Drug, Play->Drugs, NumDrug, TRUE);
- gtk_clist_sort(GTK_CLIST(ClientData.Drug.HereList));
if (IsShowingInventory) {
UpdateInventory(&ClientData.InvenDrug, Play->Drugs, NumDrug, TRUE);
}
t@@ -1287,7 +1286,6 @@ void UpdateStatus(Player *Play)
DisplayStats(Play, &ClientData.Status);
UpdateInventory(&ClientData.Drug, ClientData.Play->Drugs, NumDrug, TRUE);
- gtk_clist_sort(GTK_CLIST(ClientData.Drug.HereList));
accel_group = (GtkAccelGroup *)
g_object_get_data(G_OBJECT(ClientData.window), "accel_group");
SetJetButtonTitle(accel_group);
t@@ -1302,49 +1300,72 @@ void UpdateStatus(Player *Play)
}
}
+/* Columns in inventory list */
+enum {
+ INVEN_COL_NAME = 0,
+ INVEN_COL_NUM,
+ INVEN_COL_INDEX,
+ INVEN_NUM_COLS
+};
+
+/* Get the currently selected inventory item (drug/gun) as an index into
+ the drug/gun array, or -1 if none is selected */
+static int get_selected_inventory(GtkTreeSelection *treesel)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ if (gtk_tree_selection_get_selected(treesel, &model, &iter)) {
+ int ind;
+ gtk_tree_model_get(model, &iter, INVEN_COL_INDEX, &ind, -1);
+ return ind;
+ } else {
+ return -1;
+ }
+}
+
+static void scroll_to_selection(GtkTreeModel *model, GtkTreePath *path,
+ GtkTreeIter *iter, gpointer data)
+{
+ GtkTreeView *tv = data;
+ gtk_tree_view_scroll_to_cell(tv, path, NULL, FALSE, 0., 0.);
+}
+
void UpdateInventory(struct InventoryWidgets *Inven,
Inventory *Objects, int NumObjects, gboolean AreDrugs)
{
GtkWidget *herelist, *carrylist;
- gint i, row, selectrow[2];
- gpointer rowdata;
+ gint i;
price_t price;
gchar *titles[2];
gboolean CanBuy = FALSE, CanSell = FALSE, CanDrop = FALSE;
- GList *glist[2], *selection;
- GtkCList *clist[2];
- int numlist;
+ GtkTreeIter iter;
+ GtkTreeView *tv[2];
+ GtkListStore *carrystore, *herestore;
+ int numlist, selectrow[2];
herelist = Inven->HereList;
carrylist = Inven->CarriedList;
numlist = (herelist ? 2 : 1);
- /* Make lists of the current selections */
- clist[0] = GTK_CLIST(carrylist);
+ /* Get current selections */
+ tv[0] = GTK_TREE_VIEW(carrylist);
+ carrystore = GTK_LIST_STORE(gtk_tree_view_get_model(tv[0]));
if (herelist) {
- clist[1] = GTK_CLIST(herelist);
+ tv[1] = GTK_TREE_VIEW(herelist);
+ herestore = GTK_LIST_STORE(gtk_tree_view_get_model(tv[1]));
} else {
- clist[1] = NULL;
+ tv[1] = NULL;
}
for (i = 0; i < numlist; i++) {
- glist[i] = NULL;
- selectrow[i] = -1;
- for (selection = clist[i]->selection; selection;
- selection = g_list_next(selection)) {
- row = GPOINTER_TO_INT(selection->data);
- rowdata = gtk_clist_get_row_data(clist[i], row);
- glist[i] = g_list_append(glist[i], rowdata);
- }
+ selectrow[i] = get_selected_inventory(gtk_tree_view_get_selection(tv[i]));
}
- gtk_clist_freeze(GTK_CLIST(carrylist));
- gtk_clist_clear(GTK_CLIST(carrylist));
+ gtk_list_store_clear(carrystore);
if (herelist) {
- gtk_clist_freeze(GTK_CLIST(herelist));
- gtk_clist_clear(GTK_CLIST(herelist));
+ gtk_list_store_clear(herestore);
}
for (i = 0; i < NumObjects; i++) {
t@@ -1361,12 +1382,13 @@ void UpdateInventory(struct InventoryWidgets *Inven,
if (herelist && price > 0) {
CanBuy = TRUE;
titles[1] = FormatPrice(price);
- row = gtk_clist_append(GTK_CLIST(herelist), titles);
+ gtk_list_store_append(herestore, &iter);
+ gtk_list_store_set(herestore, &iter, INVEN_COL_NAME, titles[0],
+ INVEN_COL_NUM, titles[1], INVEN_COL_INDEX, i, -1);
g_free(titles[1]);
- gtk_clist_set_row_data(GTK_CLIST(herelist), row, GINT_TO_POINTER(i));
- if (g_list_find(glist[1], GINT_TO_POINTER(i))) {
- selectrow[1] = row;
- gtk_clist_select_row(GTK_CLIST(herelist), row, 0);
+ if (i == selectrow[1]) {
+ gtk_tree_selection_select_iter(gtk_tree_view_get_selection(tv[1]),
+ &iter);
}
}
t@@ -1383,30 +1405,22 @@ void UpdateInventory(struct InventoryWidgets *Inven,
} else {
titles[1] = g_strdup_printf("%d", Objects[i].Carried);
}
- row = gtk_clist_append(GTK_CLIST(carrylist), titles);
+ gtk_list_store_append(carrystore, &iter);
+ gtk_list_store_set(carrystore, &iter, INVEN_COL_NAME, titles[0],
+ INVEN_COL_NUM, titles[1], INVEN_COL_INDEX, i, -1);
g_free(titles[1]);
- gtk_clist_set_row_data(GTK_CLIST(carrylist), row,
- GINT_TO_POINTER(i));
- if (g_list_find(glist[0], GINT_TO_POINTER(i))) {
- selectrow[0] = row;
- gtk_clist_select_row(GTK_CLIST(carrylist), row, 0);
+ if (i == selectrow[0]) {
+ gtk_tree_selection_select_iter(gtk_tree_view_get_selection(tv[0]),
+ &iter);
}
}
g_free(titles[0]);
}
+ /* Scroll so that selection is visible */
for (i = 0; i < numlist; i++) {
- if (selectrow[i] != -1
- && gtk_clist_row_is_visible(clist[i], selectrow[i])
- != GTK_VISIBILITY_FULL) {
- gtk_clist_moveto(clist[i], selectrow[i], 0, 0.0, 0.0);
- }
- g_list_free(glist[i]);
- }
-
- gtk_clist_thaw(GTK_CLIST(carrylist));
- if (herelist) {
- gtk_clist_thaw(GTK_CLIST(herelist));
+ gtk_tree_selection_selected_foreach(gtk_tree_view_get_selection(tv[i]),
+ scroll_to_selection, tv[i]);
}
if (Inven->vbbox) {
t@@ -1615,11 +1629,9 @@ void DealDrugs(GtkWidget *widget, gpointer data)
*optionmenu, *menuitem, *vbox, *hsep, *defbutton;
GtkAdjustment *spin_adj;
GtkAccelGroup *accel_group;
- GtkWidget *clist;
+ GtkWidget *tv;
gchar *Action;
GString *text;
- GList *selection;
- gint row;
Player *Play;
gint DrugInd, i, SelIndex, FirstInd;
gboolean DrugIndOK;
t@@ -1642,17 +1654,12 @@ void DealDrugs(GtkWidget *widget, gpointer data)
Play = ClientData.Play;
if (data == BT_BUY) {
- clist = ClientData.Drug.HereList;
+ tv = ClientData.Drug.HereList;
} else {
- clist = ClientData.Drug.CarriedList;
- }
- selection = GTK_CLIST(clist)->selection;
- if (selection) {
- row = GPOINTER_TO_INT(selection->data);
- DrugInd = GPOINTER_TO_INT(gtk_clist_get_row_data(GTK_CLIST(clist), row));
- } else {
- DrugInd = -1;
+ tv = ClientData.Drug.CarriedList;
}
+ DrugInd = get_selected_inventory(
+ gtk_tree_view_get_selection(GTK_TREE_VIEW(tv)));
DrugIndOK = FALSE;
FirstInd = -1;
t@@ -1786,24 +1793,21 @@ void DealDrugs(GtkWidget *widget, gpointer data)
void DealGuns(GtkWidget *widget, gpointer data)
{
- GtkWidget *clist, *dialog;
- GList *selection;
- gint row, GunInd;
+ GtkWidget *tv, *dialog;
+ gint GunInd;
gchar *Title;
GString *text;
dialog = gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW);
if (data == BT_BUY) {
- clist = ClientData.Gun.HereList;
+ tv = ClientData.Gun.HereList;
} else {
- clist = ClientData.Gun.CarriedList;
+ tv = ClientData.Gun.CarriedList;
}
- selection = GTK_CLIST(clist)->selection;
- if (selection) {
- row = GPOINTER_TO_INT(selection->data);
- GunInd = GPOINTER_TO_INT(gtk_clist_get_row_data(GTK_CLIST(clist), row));
- } else {
+ GunInd = get_selected_inventory(
+ gtk_tree_view_get_selection(GTK_TREE_VIEW(tv)));
+ if (GunInd < 0) {
return;
}
t@@ -1994,45 +1998,31 @@ void EndGame(void)
SoundPlay(Sounds.EndGame);
}
-static void ChangeDrugSort(GtkCList *clist, gint column,
- gpointer user_data)
+static gint DrugSortByName(GtkTreeModel *model, GtkTreeIter *a,
+ GtkTreeIter *b, gpointer data)
{
- if (column == 0) {
- DrugSortMethod = (DrugSortMethod == DS_ATOZ ? DS_ZTOA : DS_ATOZ);
- } else {
- DrugSortMethod = (DrugSortMethod == DS_CHEAPFIRST ? DS_CHEAPLAST :
- DS_CHEAPFIRST);
+ int indexa, indexb;
+ gtk_tree_model_get(model, a, INVEN_COL_INDEX, &indexa, -1);
+ gtk_tree_model_get(model, b, INVEN_COL_INDEX, &indexb, -1);
+ if (indexa < 0 || indexa >= NumDrug || indexb < 0 || indexb >= NumDrug) {
+ return 0;
}
- gtk_clist_sort(clist);
+ return g_ascii_strcasecmp(Drug[indexa].Name, Drug[indexb].Name);
}
-static gint DrugSortFunc(GtkCList *clist, gconstpointer ptr1,
- gconstpointer ptr2)
+static gint DrugSortByPrice(GtkTreeModel *model, GtkTreeIter *a,
+ GtkTreeIter *b, gpointer data)
{
- int index1, index2;
+ int indexa, indexb;
price_t pricediff;
-
- index1 = GPOINTER_TO_INT(((const GtkCListRow *)ptr1)->data);
- index2 = GPOINTER_TO_INT(((const GtkCListRow *)ptr2)->data);
- if (index1 < 0 || index1 >= NumDrug || index2 < 0 || index2 >= NumDrug) {
+ gtk_tree_model_get(model, a, INVEN_COL_INDEX, &indexa, -1);
+ gtk_tree_model_get(model, b, INVEN_COL_INDEX, &indexb, -1);
+ if (indexa < 0 || indexa >= NumDrug || indexb < 0 || indexb >= NumDrug) {
return 0;
}
-
- switch (DrugSortMethod) {
- case DS_ATOZ:
- return g_ascii_strncasecmp(Drug[index1].Name, Drug[index2].Name, strlen(Drug[index2].Name));
- case DS_ZTOA:
- return g_ascii_strncasecmp(Drug[index2].Name, Drug[index1].Name, strlen(Drug[index1].Name));
- case DS_CHEAPFIRST:
- pricediff = ClientData.Play->Drugs[index1].Price -
- ClientData.Play->Drugs[index2].Price;
- return pricediff == 0 ? 0 : pricediff < 0 ? -1 : 1;
- case DS_CHEAPLAST:
- pricediff = ClientData.Play->Drugs[index2].Price -
- ClientData.Play->Drugs[index1].Price;
- return pricediff == 0 ? 0 : pricediff < 0 ? -1 : 1;
- }
- return 0;
+ pricediff = ClientData.Play->Drugs[indexa].Price -
+ ClientData.Play->Drugs[indexb].Price;
+ return pricediff == 0 ? 0 : pricediff < 0 ? -1 : 1;
}
void UpdateMenus(void)
t@@ -2200,8 +2190,10 @@ gboolean GtkLoop(int *argc, char **argv[],
#endif
{
GtkWidget *window, *vbox, *vbox2, *hbox, *frame, *table, *menubar, *text,
- *vpaned, *button, *clist, *widget;
+ *vpaned, *button, *tv, *widget;
GtkAccelGroup *accel_group;
+ GtkTreeSortable *sortable;
+ int i;
DPGtkItemFactory *item_factory;
gint nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
t@@ -2309,11 +2301,15 @@ gboolean GtkLoop(int *argc, char **argv[],
hbox = gtk_hbox_new(FALSE, 7);
CreateInventory(hbox, Names.Drugs, accel_group, TRUE, TRUE,
&ClientData.Drug, G_CALLBACK(DealDrugs));
- clist = ClientData.Drug.HereList;
- gtk_clist_column_titles_active(GTK_CLIST(clist));
- gtk_clist_set_compare_func(GTK_CLIST(clist), DrugSortFunc);
- g_signal_connect(G_OBJECT(clist), "click-column",
- G_CALLBACK(ChangeDrugSort), NULL);
+ tv = ClientData.Drug.HereList;
+ gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(tv), TRUE);
+ sortable = GTK_TREE_SORTABLE(gtk_tree_view_get_model(GTK_TREE_VIEW(tv)));
+ gtk_tree_sortable_set_sort_func(sortable, 0, DrugSortByName, NULL, NULL);
+ gtk_tree_sortable_set_sort_func(sortable, 1, DrugSortByPrice, NULL, NULL);
+ for (i = 0; i < 2; ++i) {
+ GtkTreeViewColumn *col = gtk_tree_view_get_column(GTK_TREE_VIEW(tv), i);
+ gtk_tree_view_column_set_sort_column_id(col, i);
+ }
button = ClientData.JetButton = gtk_button_new_with_label("");
ClientData.JetAccel = 0;
t@@ -3057,8 +3053,11 @@ void CreateInventory(GtkWidget *hbox, gchar *Objects,
gboolean CreateHere, struct InventoryWidgets *widgets,
GCallback CallBack)
{
- GtkWidget *scrollwin, *clist, *vbbox, *frame[2], *button[3];
- gint i, mini;
+ GtkWidget *scrollwin, *tv, *vbbox, *frame[2], *button[3];
+ GtkCellRenderer *renderer;
+ GtkListStore *store;
+ GtkTreeSelection *treesel;
+ gint i, mini, icol;
GString *text;
gchar *titles[2][2];
gchar *button_text[3];
t@@ -3096,21 +3095,37 @@ void CreateInventory(GtkWidget *hbox, gchar *Objects,
GtkWidget *hbox2 = gtk_hbox_new(TRUE, 0);
gtk_container_set_border_width(GTK_CONTAINER(frame[i]), 3);
- clist = gtk_scrolled_clist_new_with_titles(2, titles[i], &scrollwin);
- gtk_clist_set_column_auto_resize(GTK_CLIST(clist), 0, TRUE);
- gtk_clist_set_column_auto_resize(GTK_CLIST(clist), 1, TRUE);
- gtk_clist_column_titles_passive(GTK_CLIST(clist));
- gtk_clist_set_selection_mode(GTK_CLIST(clist), GTK_SELECTION_SINGLE);
- gtk_clist_set_auto_sort(GTK_CLIST(clist), FALSE);
+ tv = gtk_scrolled_tree_view_new(&scrollwin);
+ renderer = gtk_cell_renderer_text_new();
+ store = gtk_list_store_new(INVEN_NUM_COLS, G_TYPE_STRING,
+ G_TYPE_STRING, G_TYPE_INT);
+ gtk_tree_view_set_model(GTK_TREE_VIEW(tv), GTK_TREE_MODEL(store));
+ g_object_unref(store);
+ for (icol = 0; icol < 2; ++icol) {
+ GtkTreeViewColumn *col;
+ if (i == 0 && icol == 1) {
+ /* Right align prices */
+ GtkCellRenderer *rren = gtk_cell_renderer_text_new();
+ g_object_set(G_OBJECT(rren), "xalign", 1.0, NULL);
+ col = gtk_tree_view_column_new_with_attributes(
+ titles[i][icol], rren, "text", icol, NULL);
+ gtk_tree_view_column_set_alignment(col, 1.0);
+ } else {
+ col = gtk_tree_view_column_new_with_attributes(
+ titles[i][icol], renderer, "text", icol, NULL);
+ }
+ gtk_tree_view_insert_column(GTK_TREE_VIEW(tv), col, -1);
+ }
+ gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(tv), FALSE);
+ treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tv));
+ gtk_tree_selection_set_mode(treesel, GTK_SELECTION_SINGLE);
gtk_box_pack_start(GTK_BOX(hbox2), scrollwin, TRUE, TRUE, 0);
gtk_container_set_border_width(GTK_CONTAINER(hbox2), 3);
gtk_container_add(GTK_CONTAINER(frame[i]), hbox2);
if (i == 0) {
- gtk_clist_set_column_justification(GTK_CLIST(clist), 1,
- GTK_JUSTIFY_RIGHT);
- widgets->HereList = clist;
+ widgets->HereList = tv;
} else {
- widgets->CarriedList = clist;
+ widgets->CarriedList = tv;
}
}
if (CreateHere) {