tAdd basic implementation of GtkTreeView for Win32 - vaccinewars - be a doctor … | |
git clone git://src.adamsgaard.dk/vaccinewars | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit 413ccf896069ec3ba59b67b3e28cc4d2553b3251 | |
parent edb979cbb0c6aecaf43a43f01e58899723b6d47c | |
Author: Ben Webb <[email protected]> | |
Date: Thu, 19 Nov 2020 18:55:57 -0800 | |
Add basic implementation of GtkTreeView for Win32 | |
Add stub functions to implement GtkTreeView and | |
related classes, so that our GUI client and server | |
using GtkTreeView will compile on Win32. This is not | |
yet a complete functional implementation. | |
Diffstat: | |
M src/gtkport/Makefile.am | 2 +- | |
M src/gtkport/gtkenums.h | 7 +++++++ | |
M src/gtkport/gtkport.c | 1 + | |
M src/gtkport/gtkport.h | 2 ++ | |
A src/gtkport/treeview.c | 973 +++++++++++++++++++++++++++++… | |
A src/gtkport/treeview.h | 158 +++++++++++++++++++++++++++++… | |
M src/gui_client/newgamedia.c | 11 +++-------- | |
7 files changed, 1145 insertions(+), 9 deletions(-) | |
--- | |
diff --git a/src/gtkport/Makefile.am b/src/gtkport/Makefile.am | |
t@@ -1,5 +1,5 @@ | |
noinst_LIBRARIES = libgtkport.a | |
libgtkport_a_SOURCES = gtkport.c gtkport.h clist.c clist.h gtkenums.h \ | |
- unicodewrap.c unicodewrap.h | |
+ unicodewrap.c unicodewrap.h treeview.h treeview.c | |
AM_CPPFLAGS= -I../../intl -I${srcdir} -I${srcdir}/.. -I../.. @GTK_CFLAGS@ @GLI… | |
DEFS = @DEFS@ | |
diff --git a/src/gtkport/gtkenums.h b/src/gtkport/gtkenums.h | |
t@@ -121,6 +121,13 @@ typedef enum | |
GTK_WIN_POS_CENTER_ON_PARENT | |
} GtkWindowPosition; | |
+enum | |
+{ | |
+ G_TYPE_STRING, | |
+ G_TYPE_UINT, | |
+ G_TYPE_POINTER | |
+}; | |
+ | |
#endif /* CYGWIN */ | |
#endif /* __GTKENUMS_H__ */ | |
diff --git a/src/gtkport/gtkport.c b/src/gtkport/gtkport.c | |
t@@ -1294,6 +1294,7 @@ void win32_init(HINSTANCE hInstance, HINSTANCE hPrevInst… | |
myRegisterClass(&wc); | |
InitCListClass(hInstance); | |
+ InitTreeViewClass(hInstance); | |
} | |
} | |
diff --git a/src/gtkport/gtkport.h b/src/gtkport/gtkport.h | |
t@@ -172,6 +172,7 @@ struct _GtkContainer { | |
}; | |
#include "clist.h" | |
+#include "treeview.h" | |
struct _GtkMisc { | |
GtkWidget widget; | |
t@@ -579,6 +580,7 @@ void gtk_main_quit(); | |
void gtk_main(); | |
guint gtk_signal_connect(GtkObject *object, const gchar *name, | |
GtkSignalFunc func, gpointer func_data); | |
+#define g_signal_connect gtk_signal_connect | |
guint gtk_signal_connect_object(GtkObject *object, const gchar *name, | |
GtkSignalFunc func, | |
GtkObject *slot_object); | |
diff --git a/src/gtkport/treeview.c b/src/gtkport/treeview.c | |
t@@ -0,0 +1,973 @@ | |
+/************************************************************************ | |
+ * treeview.c GtkTreeView (and friends) implementation for gtkport * | |
+ * Copyright (C) 1998-2020 Ben Webb * | |
+ * Email: [email protected] * | |
+ * WWW: https://dopewars.sourceforge.io/ * | |
+ * * | |
+ * 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., 59 Temple Place - Suite 330, Boston, * | |
+ * MA 02111-1307, USA. * | |
+ ************************************************************************/ | |
+ | |
+#ifdef HAVE_CONFIG_H | |
+#include <config.h> | |
+#endif | |
+ | |
+#include "gtkport.h" | |
+ | |
+#ifdef CYGWIN | |
+ | |
+#include <winsock2.h> | |
+#include <windows.h> | |
+#include <commctrl.h> | |
+ | |
+#include "unicodewrap.h" | |
+ | |
+#define LISTITEMHPACK 3 | |
+#define LISTHEADERPACK 6 | |
+ | |
+static const gchar *WC_GTKTREEVIEWHDR = "WC_GTKTREEVIEWHDR"; | |
+ | |
+static WNDPROC wpOrigListProc; | |
+ | |
+static void gtk_tree_view_size_request(GtkWidget *widget, | |
+ GtkRequisition *requisition); | |
+static void gtk_tree_view_set_size(GtkWidget *widget, | |
+ GtkAllocation *allocation); | |
+static gboolean gtk_tree_view_wndproc(GtkWidget *widget, UINT msg, | |
+ WPARAM wParam, LPARAM lParam, gboolean *dodef); | |
+static void gtk_tree_view_realize(GtkWidget *widget); | |
+static void gtk_tree_view_destroy(GtkWidget *widget); | |
+static void gtk_tree_view_show(GtkWidget *widget); | |
+static void gtk_tree_view_hide(GtkWidget *widget); | |
+static void gtk_tree_view_draw_row(GtkTreeView *tv, LPDRAWITEMSTRUCT lpdis); | |
+static void gtk_tree_view_update_selection(GtkWidget *widget); | |
+static void gtk_tree_view_update_widths(GtkTreeView *tv, GtkTreeModel *model, | |
+ GtkListStoreRow *row); | |
+static void gtk_tree_view_update_all_widths(GtkTreeView *tv); | |
+static void gtk_tree_view_do_auto_resize(GtkTreeView *tv); | |
+static void gtk_tree_view_set_column_width(GtkTreeView *tv, gint column, | |
+ gint width); | |
+static void gtk_tree_view_set_column_width_full(GtkTreeView *tv, gint column, | |
+ gint width, | |
+ gboolean ResizeHeader); | |
+ | |
+static GtkSignalType GtkTreeViewSignals[] = { | |
+ {"size_request", gtk_marshal_VOID__GPOIN, gtk_tree_view_size_request}, | |
+ {"set_size", gtk_marshal_VOID__GPOIN, gtk_tree_view_set_size}, | |
+ {"realize", gtk_marshal_VOID__VOID, gtk_tree_view_realize}, | |
+ {"destroy", gtk_marshal_VOID__VOID, gtk_tree_view_destroy}, | |
+ {"click-column", gtk_marshal_VOID__GINT, NULL}, | |
+ {"changed", gtk_marshal_VOID__GPOIN, NULL}, | |
+ {"show", gtk_marshal_VOID__VOID, gtk_tree_view_show}, | |
+ {"hide", gtk_marshal_VOID__VOID, gtk_tree_view_hide}, | |
+ {"", NULL, NULL} | |
+}; | |
+ | |
+static GtkClass GtkTreeViewClass = { | |
+ "tree_view", &GtkContainerClass, sizeof(GtkTreeView), GtkTreeViewSignals, | |
+ gtk_tree_view_wndproc | |
+}; | |
+ | |
+static void SetTreeViewHeaderSize(GtkTreeView *clist) | |
+{ | |
+ RECT rc; | |
+ HWND hWnd; | |
+ int width; | |
+ | |
+ hWnd = GTK_WIDGET(clist)->hWnd; | |
+ clist->scrollpos = GetScrollPos(hWnd, SB_HORZ); | |
+ | |
+ GetWindowRect(hWnd, &rc); | |
+ width = (int)mySendMessage(hWnd, LB_GETHORIZONTALEXTENT, 0, 0); | |
+ width = MAX(width, rc.right - rc.left) + 100; | |
+ | |
+ SetWindowPos(clist->header, HWND_TOP, -clist->scrollpos, 0, | |
+ width, clist->header_size, SWP_NOZORDER); | |
+} | |
+ | |
+static LRESULT APIENTRY ListWndProc(HWND hwnd, UINT msg, WPARAM wParam, | |
+ LPARAM lParam) | |
+{ | |
+ LRESULT retval; | |
+ GtkWidget *widget; | |
+ | |
+ widget = GTK_WIDGET(GetWindowLongPtr(hwnd, GWLP_USERDATA)); | |
+ retval = myCallWindowProc(wpOrigListProc, hwnd, msg, wParam, lParam); | |
+ | |
+ if (msg == WM_HSCROLL && widget) { | |
+ GtkTreeView *clist = GTK_TREE_VIEW(widget); | |
+ SetTreeViewHeaderSize(clist); | |
+ } | |
+ | |
+ return retval; | |
+} | |
+ | |
+gboolean gtk_tree_view_wndproc(GtkWidget *widget, UINT msg, WPARAM wParam, | |
+ LPARAM lParam, gboolean *dodef) | |
+{ | |
+ LPDRAWITEMSTRUCT lpdis; | |
+ HD_NOTIFYA FAR *phdr; | |
+ HD_NOTIFYW FAR *phdrw; | |
+ NMHDR *nmhdr; | |
+ | |
+ switch(msg) { | |
+ case WM_COMMAND: | |
+ if (lParam && HIWORD(wParam) == LBN_SELCHANGE) { | |
+ gtk_tree_view_update_selection(widget); | |
+ return FALSE; | |
+ } | |
+ break; | |
+ case WM_DRAWITEM: | |
+ lpdis = (LPDRAWITEMSTRUCT)lParam; | |
+ if (lpdis) { | |
+ gtk_tree_view_draw_row(GTK_TREE_VIEW(widget), lpdis); | |
+ *dodef = FALSE; | |
+ return TRUE; | |
+ } | |
+ break; | |
+ case WM_NOTIFY: | |
+ nmhdr = (NMHDR *)lParam; | |
+ if (nmhdr) { | |
+ switch(nmhdr->code) { | |
+ case HDN_ENDTRACKA: | |
+ phdr = (HD_NOTIFYA FAR *)lParam; | |
+ gtk_tree_view_set_column_width_full(GTK_TREE_VIEW(widget), phdr->iItem, | |
+ phdr->pitem->cxy, FALSE); | |
+ return FALSE; | |
+ case HDN_ENDTRACKW: | |
+ phdrw = (HD_NOTIFYW FAR *)lParam; | |
+ gtk_tree_view_set_column_width_full(GTK_TREE_VIEW(widget), phdrw->iIte… | |
+ phdrw->pitem->cxy, FALSE); | |
+ return FALSE; | |
+ case HDN_ITEMCLICKA: | |
+ phdr = (HD_NOTIFYA FAR *)lParam; | |
+ gtk_signal_emit(GTK_OBJECT(widget), "click-column", (gint)phdr->iItem); | |
+ return FALSE; | |
+ case HDN_ITEMCLICKW: | |
+ phdrw = (HD_NOTIFYW FAR *)lParam; | |
+ gtk_signal_emit(GTK_OBJECT(widget), "click-column", (gint)phdrw->iItem… | |
+ return FALSE; | |
+ default: | |
+ break; | |
+ } | |
+ } | |
+ break; | |
+ } | |
+ | |
+ return FALSE; | |
+} | |
+ | |
+static void gtk_tree_view_set_extent(GtkTreeView *tv) | |
+{ | |
+ HWND hWnd; | |
+ | |
+ hWnd = GTK_WIDGET(tv)->hWnd; | |
+ if (hWnd) { | |
+ GSList *colpt; | |
+ int width = 0; | |
+ | |
+ for (colpt = tv->columns; colpt; colpt = g_slist_next(colpt)) { | |
+ GtkTreeViewColumn *col = colpt->data; | |
+ width += col->width; | |
+ } | |
+ mySendMessage(hWnd, LB_SETHORIZONTALEXTENT, (WPARAM)width, 0); | |
+ SetTreeViewHeaderSize(tv); | |
+ } | |
+} | |
+ | |
+void gtk_tree_view_set_size(GtkWidget *widget, GtkAllocation *allocation) | |
+{ | |
+ GtkTreeView *clist = GTK_TREE_VIEW(widget); | |
+ | |
+ gtk_container_set_size(widget, allocation); | |
+ if (clist->header) { | |
+ POINT pt; | |
+ pt.x = allocation->x; | |
+ pt.y = allocation->y; | |
+ MapWidgetOrigin(widget, &pt); | |
+ SetWindowPos(clist->scrollwin, HWND_TOP, pt.x, pt.y, | |
+ allocation->width, clist->header_size, SWP_NOZORDER); | |
+ allocation->y += clist->header_size - 1; | |
+ allocation->height -= clist->header_size - 1; | |
+ } | |
+ gtk_tree_view_set_extent(clist); | |
+} | |
+ | |
+GtkWidget *gtk_tree_view_new(void) | |
+{ | |
+ GtkTreeView *view; | |
+ | |
+ view = GTK_TREE_VIEW(GtkNewObject(&GtkTreeViewClass)); | |
+ view->model = NULL; | |
+ view->scrollpos = 0; | |
+ view->columns = NULL; | |
+ view->headers_clickable = TRUE; | |
+ view->mode = GTK_SELECTION_SINGLE; | |
+ view->selection = NULL; | |
+ return GTK_WIDGET(view); | |
+} | |
+ | |
+GtkTreeSelection *gtk_tree_view_get_selection(GtkTreeView *tree_view) | |
+{ | |
+ /* The selection *is* the tree view */ | |
+ return tree_view; | |
+} | |
+ | |
+void gtk_tree_view_size_request(GtkWidget *widget, GtkRequisition *requisition) | |
+{ | |
+ SIZE size; | |
+ | |
+ if (GetTextSize(widget->hWnd, "Sample text", &size, defFont)) { | |
+ requisition->width = size.cx; | |
+ requisition->height = size.cy * 6 + 12; | |
+ } | |
+} | |
+ | |
+void gtk_tree_view_realize(GtkWidget *widget) | |
+{ | |
+ HWND Parent, header, scrollwin; | |
+ HD_LAYOUT hdl; | |
+ HD_ITEM hdi; | |
+ RECT rcParent; | |
+ WINDOWPOS wp; | |
+ GtkTreeView *tv = GTK_TREE_VIEW(widget); | |
+ GSList *colpt; | |
+ gint i; | |
+ | |
+ gtk_container_realize(widget); | |
+ Parent = gtk_get_parent_hwnd(widget); | |
+ GTK_WIDGET_SET_FLAGS(widget, GTK_CAN_FOCUS); | |
+ rcParent.left = rcParent.top = 0; | |
+ rcParent.right = rcParent.bottom = 800; | |
+ scrollwin = myCreateWindow(WC_GTKTREEVIEWHDR, NULL, WS_CHILD | WS_BORDER, | |
+ 0, 0, 0, 0, Parent, NULL, hInst, NULL); | |
+ SetWindowLongPtr(scrollwin, GWLP_USERDATA, (LONG_PTR)widget); | |
+ header = myCreateWindowEx(0, WC_HEADER, NULL, | |
+ WS_CHILD | HDS_HORZ | WS_VISIBLE | |
+ | (tv->headers_clickable ? HDS_BUTTONS : 0), | |
+ 0, 0, 0, 0, scrollwin, NULL, hInst, NULL); | |
+ SetWindowLongPtr(header, GWLP_USERDATA, (LONG_PTR)widget); | |
+ tv->header = header; | |
+ tv->scrollwin = scrollwin; | |
+ gtk_set_default_font(header); | |
+ hdl.prc = &rcParent; | |
+ hdl.pwpos = ℘ | |
+ mySendMessage(header, HDM_LAYOUT, 0, (LPARAM)&hdl); | |
+ tv->header_size = wp.cy; | |
+ widget->hWnd = myCreateWindowEx(WS_EX_CLIENTEDGE, "LISTBOX", "", | |
+ WS_CHILD | WS_TABSTOP | WS_VSCROLL | |
+ | WS_HSCROLL | LBS_OWNERDRAWFIXED | |
+ | LBS_NOTIFY, 0, 0, 0, 0, Parent, NULL, | |
+ hInst, NULL); | |
+ /* Subclass the window */ | |
+ wpOrigListProc = (WNDPROC)mySetWindowLong(widget->hWnd, GWLP_WNDPROC, | |
+ (LONG_PTR)ListWndProc); | |
+ gtk_set_default_font(widget->hWnd); | |
+ | |
+ if (tv->model) { | |
+ for (i = 0; i < tv->model->rows->len; ++i) { | |
+ mySendMessage(widget->hWnd, LB_ADDSTRING, 0, 1); | |
+ } | |
+ } | |
+ gtk_tree_view_update_all_widths(tv); | |
+ | |
+ for (colpt = tv->columns, i = 0; colpt; colpt = g_slist_next(colpt), ++i) { | |
+ GtkTreeViewColumn *col = colpt->data; | |
+ if (col->auto_resize) { | |
+ col->width = col->optimal_width; | |
+ } | |
+ hdi.mask = HDI_TEXT | HDI_FORMAT | HDI_WIDTH; | |
+ hdi.pszText = col->title; | |
+ if (hdi.pszText) { | |
+ if (!g_slist_next(colpt)) | |
+ hdi.cxy = 9000; | |
+ else | |
+ hdi.cxy = col->width; | |
+ hdi.cchTextMax = strlen(hdi.pszText); | |
+ hdi.fmt = HDF_LEFT | HDF_STRING; | |
+ myHeader_InsertItem(header, i + 1, &hdi); | |
+ } | |
+ } | |
+} | |
+ | |
+static void gtk_list_store_row_free(GtkListStoreRow *row, GtkListStore *store) | |
+{ | |
+ int i; | |
+ for (i = 0; i < store->ncols; ++i) { | |
+ if (store->coltype[i] == G_TYPE_STRING) { | |
+ g_free(row->data[i]); | |
+ } | |
+ } | |
+} | |
+ | |
+void gtk_list_store_clear(GtkListStore *list_store) | |
+{ | |
+ guint i; | |
+ for (i = 0; i < list_store->rows->len; ++i) { | |
+ GtkListStoreRow *row = &g_array_index(list_store->rows, GtkListStoreRow, i… | |
+ gtk_list_store_row_free(row, list_store); | |
+ } | |
+ g_array_set_size(list_store->rows, 0); | |
+ | |
+ if (list_store->view) { | |
+ HWND hWnd; | |
+ gtk_tree_view_update_all_widths(list_store->view); | |
+ hWnd = GTK_WIDGET(list_store->view)->hWnd; | |
+ if (hWnd) { | |
+ mySendMessage(hWnd, LB_RESETCONTENT, 0, 0); | |
+ } | |
+ } | |
+} | |
+ | |
+void gtk_list_store_insert(GtkListStore *list_store, GtkTreeIter *iter, | |
+ gint position) | |
+{ | |
+ GtkListStoreRow row; | |
+ /* Add a new empty row to the store and return a pointer to it */ | |
+ row.data = g_new0(gpointer, list_store->ncols); | |
+ if (position < 0) { | |
+ g_array_append_val(list_store->rows, row); | |
+ *iter = list_store->rows->len - 1; | |
+ } else { | |
+ g_array_insert_val(list_store->rows, position, row); | |
+ *iter = position; | |
+ } | |
+} | |
+ | |
+void gtk_list_store_append(GtkListStore *list_store, GtkTreeIter *iter) | |
+{ | |
+ gtk_list_store_insert(list_store, iter, -1); | |
+} | |
+ | |
+void gtk_list_store_set(GtkListStore *list_store, GtkTreeIter *iter, ...) | |
+{ | |
+ va_list ap; | |
+ int colind; | |
+ GtkListStoreRow *row = &g_array_index(list_store->rows, GtkListStoreRow, | |
+ *iter); | |
+ | |
+ va_start(ap, iter); | |
+ while ((colind = va_arg(ap, int)) >= 0) { | |
+ switch(list_store->coltype[colind]) { | |
+ case G_TYPE_STRING: | |
+ g_free(row->data[colind]); /* Free any existing string */ | |
+ row->data[colind] = g_strdup(va_arg(ap, const char*)); | |
+ break; | |
+ case G_TYPE_UINT: | |
+ row->data[colind] = GINT_TO_POINTER(va_arg(ap, unsigned)); | |
+ break; | |
+ case G_TYPE_POINTER: | |
+ row->data[colind] = va_arg(ap, gpointer); | |
+ break; | |
+ } | |
+ } | |
+ va_end(ap); | |
+ | |
+ if (list_store->view) { | |
+ GtkWidget *widget = GTK_WIDGET(list_store->view); | |
+ | |
+ gtk_tree_view_update_widths(list_store->view, list_store, row); | |
+ gtk_tree_view_do_auto_resize(list_store->view); | |
+ | |
+ if (GTK_WIDGET_REALIZED(widget)) { | |
+ HWND hWnd = widget->hWnd; | |
+ mySendMessage(hWnd, LB_INSERTSTRING, (WPARAM)*iter, 1); | |
+ } | |
+ } | |
+} | |
+ | |
+void gtk_tree_model_get(GtkTreeModel *tree_model, GtkTreeIter *iter, ...) | |
+{ | |
+ va_list ap; | |
+ char **strpt; | |
+ unsigned *uintpt; | |
+ gpointer *ptpt; | |
+ int colind; | |
+ GtkListStoreRow *row = &g_array_index(tree_model->rows, GtkListStoreRow, | |
+ *iter); | |
+ | |
+ va_start(ap, iter); | |
+ while ((colind = va_arg(ap, int)) >= 0) { | |
+ switch(tree_model->coltype[colind]) { | |
+ case G_TYPE_STRING: | |
+ strpt = va_arg(ap, char **); | |
+ *strpt = g_strdup(row->data[colind]); | |
+ break; | |
+ case G_TYPE_UINT: | |
+ uintpt = va_arg(ap, unsigned *); | |
+ *uintpt = GPOINTER_TO_INT(row->data[colind]); | |
+ break; | |
+ case G_TYPE_POINTER: | |
+ ptpt = va_arg(ap, gpointer *); | |
+ *ptpt = row->data[colind]; | |
+ break; | |
+ } | |
+ } | |
+ va_end(ap); | |
+} | |
+ | |
+static void gtk_tree_view_column_free(gpointer data) | |
+{ | |
+ GtkTreeViewColumn *col = data; | |
+ g_free(col->title); | |
+ g_free(col); | |
+} | |
+ | |
+static void gtk_tree_model_free(GtkTreeModel *model) | |
+{ | |
+ gtk_list_store_clear(model); /* Remove all rows */ | |
+ g_array_free(model->rows, TRUE); | |
+ g_free(model->coltype); | |
+ g_free(model); | |
+} | |
+ | |
+void gtk_tree_view_destroy(GtkWidget *widget) | |
+{ | |
+ GtkTreeView *view = GTK_TREE_VIEW(widget); | |
+ g_slist_free_full(view->columns, gtk_tree_view_column_free); | |
+ view->columns = NULL; | |
+ if (view->model) { | |
+ gtk_tree_model_free(view->model); | |
+ } | |
+ view->model = NULL; | |
+} | |
+ | |
+void gtk_tree_view_show(GtkWidget *widget) | |
+{ | |
+ if (GTK_WIDGET_REALIZED(widget)) { | |
+ ShowWindow(GTK_TREE_VIEW(widget)->scrollwin, SW_SHOWNORMAL); | |
+ } | |
+} | |
+ | |
+void gtk_tree_view_hide(GtkWidget *widget) | |
+{ | |
+ if (GTK_WIDGET_REALIZED(widget)) { | |
+ ShowWindow(GTK_TREE_VIEW(widget)->scrollwin, SW_HIDE); | |
+ } | |
+} | |
+ | |
+/* Draw an individual cell (row+column) */ | |
+static void draw_cell_text(GtkTreeViewColumn *col, GtkTreeModel *model, | |
+ LPDRAWITEMSTRUCT lpdis, GtkListStoreRow *row, | |
+ RECT *rcCol) | |
+{ | |
+ UINT align; | |
+ char *val; | |
+ int modcol = col->model_column; | |
+ switch(col->justification) { | |
+ case GTK_JUSTIFY_RIGHT: | |
+ align = DT_RIGHT; | |
+ break; | |
+ case GTK_JUSTIFY_CENTER: | |
+ align = DT_CENTER; | |
+ break; | |
+ default: | |
+ align = DT_LEFT; | |
+ break; | |
+ } | |
+ align |= DT_SINGLELINE | DT_VCENTER | DT_END_ELLIPSIS; | |
+ | |
+ switch(model->coltype[modcol]) { | |
+ case G_TYPE_STRING: | |
+ if (row->data[modcol]) { | |
+ myDrawText(lpdis->hDC, row->data[modcol], -1, rcCol, align); | |
+ } | |
+ break; | |
+ case G_TYPE_UINT: | |
+ val = g_strdup_printf("%d", GPOINTER_TO_INT(row->data[modcol])); | |
+ myDrawText(lpdis->hDC, val, -1, rcCol, align); | |
+ g_free(val); | |
+ break; | |
+ } | |
+} | |
+ | |
+void gtk_tree_view_draw_row(GtkTreeView *tv, LPDRAWITEMSTRUCT lpdis) | |
+{ | |
+ HBRUSH bkgrnd; | |
+ COLORREF textcol, oldtextcol; | |
+ RECT rcCol; | |
+ int oldbkmode; | |
+ guint nrows; | |
+ gint CurrentX, right; | |
+ GtkListStoreRow *row; | |
+ | |
+ if (lpdis->itemState & ODS_SELECTED) { | |
+ bkgrnd = (HBRUSH)(1 + COLOR_HIGHLIGHT); | |
+ textcol = (COLORREF)GetSysColor(COLOR_HIGHLIGHTTEXT); | |
+ } else { | |
+ bkgrnd = (HBRUSH)(1 + COLOR_WINDOW); | |
+ textcol = (COLORREF)GetSysColor(COLOR_WINDOWTEXT); | |
+ } | |
+ oldtextcol = SetTextColor(lpdis->hDC, textcol); | |
+ oldbkmode = SetBkMode(lpdis->hDC, TRANSPARENT); | |
+ FillRect(lpdis->hDC, &lpdis->rcItem, bkgrnd); | |
+ | |
+ nrows = tv->model ? tv->model->rows->len : 0; | |
+ if (lpdis->itemID >= 0 && lpdis->itemID < nrows) { | |
+ int width; | |
+ GSList *colpt; | |
+ row = &g_array_index(tv->model->rows, GtkListStoreRow, lpdis->itemID); | |
+ width = CurrentX = 0; | |
+ for (colpt = tv->columns; colpt; colpt = g_slist_next(colpt)) { | |
+ GtkTreeViewColumn *col = colpt->data; | |
+ width += col->width; | |
+ } | |
+ right = MAX(lpdis->rcItem.right, width); | |
+ rcCol.top = lpdis->rcItem.top; | |
+ rcCol.bottom = lpdis->rcItem.bottom; | |
+ if (row->data) | |
+ for (colpt = tv->columns; colpt; colpt = g_slist_next(colpt)) { | |
+ GtkTreeViewColumn *col = colpt->data; | |
+ rcCol.left = CurrentX + LISTITEMHPACK; | |
+ CurrentX += col->width; | |
+ rcCol.right = CurrentX - LISTITEMHPACK; | |
+ if (rcCol.left > right) | |
+ rcCol.left = right; | |
+ if (rcCol.right > right - LISTITEMHPACK) | |
+ rcCol.right = right - LISTITEMHPACK; | |
+ if (!g_slist_next(colpt)) | |
+ rcCol.right = right - LISTITEMHPACK; | |
+ draw_cell_text(col, tv->model, lpdis, row, &rcCol); | |
+ } | |
+ } | |
+ | |
+ SetTextColor(lpdis->hDC, oldtextcol); | |
+ SetBkMode(lpdis->hDC, oldbkmode); | |
+ if (lpdis->itemState & ODS_FOCUS) { | |
+ DrawFocusRect(lpdis->hDC, &lpdis->rcItem); | |
+ } | |
+} | |
+ | |
+void gtk_tree_view_do_auto_resize(GtkTreeView *tv) | |
+{ | |
+ GSList *colpt; | |
+ gint i; | |
+ | |
+ for (colpt = tv->columns, i = 0; colpt; colpt = g_slist_next(colpt), i++) { | |
+ GtkTreeViewColumn *col = colpt->data; | |
+ if (col->auto_resize) { | |
+ gtk_tree_view_set_column_width(tv, i, col->optimal_width); | |
+ } | |
+ } | |
+} | |
+ | |
+gint gtk_tree_view_optimal_column_width(GtkTreeView *tv, gint column) | |
+{ | |
+ GtkTreeViewColumn *col = g_slist_nth_data(tv->columns, column); | |
+ return col->optimal_width; | |
+} | |
+ | |
+void gtk_tree_view_update_all_widths(GtkTreeView *tv) | |
+{ | |
+ SIZE size; | |
+ HWND header; | |
+ gint i; | |
+ | |
+ header = tv->header; | |
+ if (header) { | |
+ GSList *colpt; | |
+ for (colpt = tv->columns, i = 0; colpt; colpt = g_slist_next(colpt), i++) { | |
+ GtkTreeViewColumn *col = colpt->data; | |
+ if (GetTextSize(header, col->title, &size, defFont)) { | |
+ int new_width = size.cx + 4 + 2 * LISTHEADERPACK; | |
+ col->width = MAX(col->width, new_width); | |
+ col->optimal_width = MAX(col->optimal_width, new_width); | |
+ } | |
+ } | |
+ } | |
+ | |
+ if (tv->model) { | |
+ for (i = 0; i < tv->model->rows->len; ++i) { | |
+ GtkListStoreRow *row = &g_array_index(tv->model->rows, | |
+ GtkListStoreRow, i); | |
+ gtk_tree_view_update_widths(tv, tv->model, row); | |
+ } | |
+ } | |
+ | |
+ gtk_tree_view_set_extent(tv); | |
+} | |
+ | |
+void gtk_tree_view_update_widths(GtkTreeView *tv, GtkTreeModel *model, | |
+ GtkListStoreRow *row) | |
+{ | |
+ SIZE size; | |
+ GSList *colpt; | |
+ HWND hWnd; | |
+ | |
+ hWnd = GTK_WIDGET(tv)->hWnd; | |
+ if (!hWnd) | |
+ return; | |
+ for (colpt = tv->columns; colpt; colpt = g_slist_next(colpt)) { | |
+ GtkTreeViewColumn *col = colpt->data; | |
+ int modcol = col->model_column; | |
+ char *text; | |
+ switch (model->coltype[modcol]) { | |
+ case G_TYPE_STRING: | |
+ text = row->data[modcol]; | |
+ break; | |
+ case G_TYPE_UINT: | |
+ text = "9999"; /* hack */ | |
+ break; | |
+ default: | |
+ text = NULL; | |
+ } | |
+ if (text && GetTextSize(hWnd, text, &size, defFont)) { | |
+ int new_width = size.cx + 4 + 2 * LISTITEMHPACK; | |
+ col->optimal_width = MAX(col->optimal_width, new_width); | |
+ } | |
+ } | |
+} | |
+ | |
+gboolean gtk_list_store_remove(GtkListStore *list_store, GtkTreeIter *iter) | |
+{ | |
+ gint rowind = *iter; | |
+ if (rowind >= 0 && rowind < list_store->rows->len) { | |
+ GtkListStoreRow *row = &g_array_index(list_store->rows, | |
+ GtkListStoreRow, rowind); | |
+ gtk_list_store_row_free(row, list_store); | |
+ g_array_remove_index(list_store->rows, rowind); | |
+ | |
+ if (list_store->view && GTK_WIDGET_REALIZED(GTK_WIDGET(list_store->view)))… | |
+ HWND hWnd = GTK_WIDGET(list_store->view)->hWnd; | |
+ | |
+ mySendMessage(hWnd, LB_DELETESTRING, (WPARAM)rowind, 0); | |
+ } | |
+ return TRUE; | |
+ } else { | |
+ return FALSE; | |
+ } | |
+} | |
+ | |
+GtkWidget *gtk_scrolled_tree_view_new(GtkWidget **pack_widg) | |
+{ | |
+ GtkWidget *widget; | |
+ | |
+ widget = gtk_tree_view_new(); | |
+ *pack_widg = widget; | |
+ return widget; | |
+} | |
+ | |
+void gtk_tree_view_set_column_width(GtkTreeView *tv, gint column, gint width) | |
+{ | |
+ gtk_tree_view_set_column_width_full(tv, column, width, TRUE); | |
+} | |
+ | |
+void gtk_tree_view_set_column_width_full(GtkTreeView *tv, gint column, | |
+ gint width, gboolean ResizeHeader) | |
+{ | |
+ int ncols; | |
+ GtkTreeViewColumn *col; | |
+ HWND hWnd, header; | |
+ HD_ITEM hdi; | |
+ | |
+ ncols = g_slist_length(tv->columns); | |
+ if (column < 0 || column >= ncols) | |
+ return; | |
+ col = g_slist_nth_data(tv->columns, column); | |
+ | |
+ col->width = width; | |
+ if (GTK_WIDGET_REALIZED(GTK_WIDGET(tv))) { | |
+ header = tv->header; | |
+ if (ResizeHeader && header) { | |
+ hdi.mask = HDI_WIDTH; | |
+ if (column == ncols - 1) | |
+ width = 9000; | |
+ hdi.cxy = width; | |
+ if (mySendMessage(header, HDM_GETITEM, (WPARAM)column, (LPARAM)&hdi) | |
+ && hdi.cxy != width) { | |
+ hdi.mask = HDI_WIDTH; | |
+ hdi.cxy = width; | |
+ mySendMessage(header, HDM_SETITEM, (WPARAM)column, (LPARAM)&hdi); | |
+ } | |
+ } | |
+ gtk_tree_view_set_extent(tv); | |
+ hWnd = GTK_WIDGET(tv)->hWnd; | |
+ if (hWnd) | |
+ InvalidateRect(hWnd, NULL, FALSE); | |
+ } | |
+} | |
+ | |
+void gtk_tree_selection_set_mode(GtkTreeSelection *selection, | |
+ GtkSelectionMode type) | |
+{ | |
+ selection->mode = type; | |
+} | |
+ | |
+void gtk_tree_selection_select_path(GtkTreeSelection *selection, | |
+ GtkTreePath *path) | |
+{ | |
+ HWND hWnd; | |
+ guint row = *path; | |
+ | |
+ hWnd = GTK_WIDGET(selection)->hWnd; | |
+ if (hWnd) { | |
+ if (selection->mode == GTK_SELECTION_SINGLE) { | |
+ mySendMessage(hWnd, LB_SETCURSEL, (WPARAM)row, 0); | |
+ } else { | |
+ mySendMessage(hWnd, LB_SETSEL, (WPARAM)TRUE, (LPARAM)row); | |
+ } | |
+ gtk_tree_view_update_selection(GTK_WIDGET(selection)); | |
+ } | |
+} | |
+ | |
+void gtk_tree_selection_unselect_path(GtkTreeSelection *selection, | |
+ GtkTreePath *path) | |
+{ | |
+ HWND hWnd; | |
+ guint row = *path; | |
+ | |
+ hWnd = GTK_WIDGET(selection)->hWnd; | |
+ if (hWnd) { | |
+ if (selection->mode == GTK_SELECTION_SINGLE) { | |
+ mySendMessage(hWnd, LB_SETCURSEL, (WPARAM)(-1), 0); | |
+ } else { | |
+ mySendMessage(hWnd, LB_SETSEL, (WPARAM)FALSE, (LPARAM)row); | |
+ } | |
+ gtk_tree_view_update_selection(GTK_WIDGET(selection)); | |
+ } | |
+} | |
+ | |
+gint gtk_tree_selection_count_selected_rows(GtkTreeSelection *selection) | |
+{ | |
+ return g_list_length(selection->selection); | |
+} | |
+ | |
+gboolean gtk_tree_selection_get_selected(GtkTreeSelection *selection, | |
+ GtkTreeModel **model, | |
+ GtkTreeIter *iter) | |
+{ | |
+ if (model) { | |
+ *model = selection->model; | |
+ } | |
+ | |
+ /* Just return the first selected row */ | |
+ if (selection->selection) { | |
+ if (iter) { | |
+ int row = GPOINTER_TO_INT(g_list_nth_data(selection->selection, 0)); | |
+ *iter = row; | |
+ } | |
+ return TRUE; | |
+ } else { | |
+ return FALSE; | |
+ } | |
+} | |
+ | |
+void gtk_tree_selection_selected_foreach(GtkTreeSelection *selection, | |
+ GtkTreeSelectionForeachFunc func, | |
+ gpointer data) | |
+{ | |
+ GList *sel; | |
+ for (sel = selection->selection; sel; sel = g_list_next(sel)) { | |
+ int row = GPOINTER_TO_INT(sel->data); | |
+ func(selection->model, &row, &row, data); | |
+ } | |
+} | |
+ | |
+void gtk_tree_view_update_selection(GtkWidget *widget) | |
+{ | |
+ GtkTreeView *tv = GTK_TREE_VIEW(widget); | |
+ gint i; | |
+ | |
+ g_list_free(tv->selection); | |
+ tv->selection = NULL; | |
+ if (widget->hWnd) { | |
+ if (tv->model) for (i = 0; i < tv->model->rows->len; i++) { | |
+ if (mySendMessage(widget->hWnd, LB_GETSEL, (WPARAM)i, 0) > 0) { | |
+ tv->selection = g_list_append(tv->selection, GINT_TO_POINTER(i)); | |
+ } | |
+ } | |
+ | |
+ gtk_signal_emit(GTK_OBJECT(widget), "changed"); | |
+ } | |
+} | |
+ | |
+static LRESULT CALLBACK TreeViewHdrWndProc(HWND hwnd, UINT msg, WPARAM wParam, | |
+ LPARAM lParam) | |
+{ | |
+ GtkWidget *widget; | |
+ gboolean retval = FALSE, dodef = TRUE; | |
+ | |
+ widget = GTK_WIDGET(GetWindowLongPtr(hwnd, GWLP_USERDATA)); | |
+ | |
+ if (widget) { | |
+ retval = gtk_tree_view_wndproc(widget, msg, wParam, lParam, &dodef); | |
+ } | |
+ | |
+ if (dodef) { | |
+ return myDefWindowProc(hwnd, msg, wParam, lParam); | |
+ } else { | |
+ return retval; | |
+ } | |
+} | |
+ | |
+void InitTreeViewClass(HINSTANCE hInstance) | |
+{ | |
+ WNDCLASS wc; | |
+ | |
+ wc.style = 0; | |
+ wc.lpfnWndProc = TreeViewHdrWndProc; | |
+ wc.cbClsExtra = 0; | |
+ wc.cbWndExtra = 0; | |
+ wc.hInstance = hInstance; | |
+ wc.hIcon = NULL; | |
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW); | |
+ wc.hbrBackground = NULL; | |
+ wc.lpszMenuName = NULL; | |
+ wc.lpszClassName = WC_GTKTREEVIEWHDR; | |
+ myRegisterClass(&wc); | |
+} | |
+ | |
+/* Make a new GtkListStore and fill in the column types */ | |
+GtkListStore *gtk_list_store_new(gint n_columns, ...) | |
+{ | |
+ GtkListStore *store; | |
+ int i; | |
+ | |
+ va_list ap; | |
+ va_start(ap, n_columns); | |
+ | |
+ store = g_new0(GtkListStore, 1); | |
+ store->view = NULL; | |
+ store->ncols = n_columns; | |
+ store->coltype = g_new(int, n_columns); | |
+ store->rows = g_array_new(FALSE, FALSE, sizeof(GtkListStoreRow)); | |
+ for (i = 0; i < n_columns; ++i) { | |
+ store->coltype[i] = va_arg(ap, int); | |
+ } | |
+ va_end(ap); | |
+ return store; | |
+} | |
+ | |
+/* We don't support customizing renderers right now */ | |
+GtkCellRenderer *gtk_cell_renderer_text_new(void) | |
+{ | |
+ return NULL; | |
+} | |
+ | |
+static GtkTreeViewColumn *new_column_internal(const char *title, va_list args) | |
+{ | |
+ GtkTreeViewColumn *col; | |
+ const char *name; | |
+ | |
+ col = g_new0(GtkTreeViewColumn, 1); | |
+ col->title = g_strdup(title); | |
+ col->resizeable = FALSE; | |
+ col->expand = FALSE; | |
+ col->model_column = -1; | |
+ | |
+ /* Currently we only support the "text" attribute to point to the | |
+ ListStore column */ | |
+ while ((name = va_arg(args, const char *)) != NULL) { | |
+ if (strcmp(name, "text") == 0) { | |
+ col->model_column = va_arg(args, int); | |
+ } | |
+ } | |
+ return col; | |
+} | |
+ | |
+GtkTreeViewColumn *gtk_tree_view_column_new_with_attributes | |
+ (const gchar *title, GtkCellRenderer *cell, ...) | |
+{ | |
+ GtkTreeViewColumn *col; | |
+ va_list args; | |
+ | |
+ va_start(args, cell); | |
+ col = new_column_internal(title, args); | |
+ va_end(args); | |
+ return col; | |
+} | |
+ | |
+gint gtk_tree_view_insert_column_with_attributes | |
+ (GtkTreeView *tree_view, gint position, const gchar *title, | |
+ GtkCellRenderer *cell, ...) | |
+{ | |
+ GtkTreeViewColumn *col; | |
+ va_list args; | |
+ | |
+ va_start(args, cell); | |
+ col = new_column_internal(title, args); | |
+ va_end(args); | |
+ return gtk_tree_view_insert_column(tree_view, col, position); | |
+} | |
+ | |
+void gtk_tree_view_column_set_resizable(GtkTreeViewColumn *tree_column, | |
+ gboolean resizable) | |
+{ | |
+ tree_column->resizeable = resizable; | |
+} | |
+ | |
+void gtk_tree_view_column_set_expand(GtkTreeViewColumn *tree_column, | |
+ gboolean expand) | |
+{ | |
+ tree_column->expand = expand; | |
+} | |
+ | |
+gint gtk_tree_view_insert_column(GtkTreeView *tree_view, | |
+ GtkTreeViewColumn *column, | |
+ gint position) | |
+{ | |
+ tree_view->columns = g_slist_insert(tree_view->columns, column, position); | |
+ return g_slist_length(tree_view->columns); | |
+} | |
+ | |
+void gtk_tree_view_set_model(GtkTreeView *tree_view, GtkTreeModel *model) | |
+{ | |
+ /* We only support a single model per view, so ignore attempts to remove it … | |
+ if (model) { | |
+ tree_view->model = model; | |
+ model->view = tree_view; | |
+ /* todo: update view if necessary */ | |
+ } | |
+} | |
+ | |
+GtkTreeModel *gtk_tree_view_get_model(GtkTreeView *tree_view) | |
+{ | |
+ return tree_view->model; | |
+} | |
+ | |
+void gtk_tree_view_set_headers_clickable(GtkTreeView *tree_view, | |
+ gboolean setting) | |
+{ | |
+ tree_view->headers_clickable = setting; | |
+} | |
+ | |
+/* These are noops; we only use these for GtkListStore, which should always | |
+ be owned (and thus freed) by our GtkTreeView */ | |
+void g_object_unref(gpointer object) | |
+{ | |
+} | |
+ | |
+gpointer g_object_ref(gpointer object) | |
+{ | |
+ return object; | |
+} | |
+ | |
+#else /* for systems with GTK+ */ | |
+ | |
+GtkWidget *gtk_scrolled_tree_view_new(GtkWidget **pack_widg) | |
+{ | |
+ GtkWidget *scrollwin, *clist; | |
+ | |
+ clist = gtk_tree_view_new(); | |
+ scrollwin = gtk_scrolled_window_new(NULL, NULL); | |
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin), | |
+ GTK_POLICY_AUTOMATIC, | |
+ GTK_POLICY_AUTOMATIC); | |
+ gtk_container_add(GTK_CONTAINER(scrollwin), clist); | |
+ *pack_widg = scrollwin; | |
+ return clist; | |
+} | |
+ | |
+#endif | |
diff --git a/src/gtkport/treeview.h b/src/gtkport/treeview.h | |
t@@ -0,0 +1,158 @@ | |
+/************************************************************************ | |
+ * treeview.h GtkTreeView (and friends) implementation for gtkport * | |
+ * Copyright (C) 1998-2020 Ben Webb * | |
+ * Email: [email protected] * | |
+ * WWW: https://dopewars.sourceforge.io/ * | |
+ * * | |
+ * 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., 59 Temple Place - Suite 330, Boston, * | |
+ * MA 02111-1307, USA. * | |
+ ************************************************************************/ | |
+ | |
+#ifndef __TREEVIEW_H__ | |
+#define __TREEVIEW_H__ | |
+ | |
+#ifdef HAVE_CONFIG_H | |
+#include <config.h> | |
+#endif | |
+ | |
+#ifdef CYGWIN | |
+ | |
+#include <glib.h> | |
+#include "gtkenums.h" | |
+ | |
+typedef struct _GtkTreeView GtkTreeView; | |
+typedef struct _GtkTreeViewColumn GtkTreeViewColumn; | |
+typedef struct _GtkListStore GtkListStore; | |
+/* ListStore is the only model we provide here, so they can be synonyms */ | |
+typedef struct _GtkListStore GtkTreeModel; | |
+typedef struct _GtkCellRenderer GtkCellRenderer; | |
+ | |
+/* We only support one selection per tree view, so make them synonyms */ | |
+typedef struct _GtkTreeView GtkTreeSelection; | |
+ | |
+/* A list row is just a list of pointers to column data */ | |
+typedef struct _GtkListStoreRow GtkListStoreRow; | |
+ | |
+/* Tree iterators and paths are eaach just a row index */ | |
+typedef guint GtkTreeIter; | |
+typedef guint GtkTreePath; | |
+ | |
+struct _GtkTreeView { | |
+ GtkContainer container; | |
+ HWND header, scrollwin; | |
+ GtkTreeModel *model; | |
+ int scrollpos; | |
+ gint16 header_size; | |
+ GtkSelectionMode mode; | |
+ GSList *columns; /* List of GtkTreeViewColumn objects */ | |
+ GList *selection; | |
+ gint headers_clickable:1; | |
+}; | |
+ | |
+struct _GtkTreeViewColumn { | |
+ gchar *title; /* header title */ | |
+ int model_column; /* the index of the column in the GtkTreeModel */ | |
+ gint width; | |
+ gint optimal_width; | |
+ GtkJustification justification; | |
+ guint visible:1; | |
+ guint resizeable:1; | |
+ guint auto_resize:1; | |
+ guint expand:1; /* should the column take up available space? */ | |
+}; | |
+ | |
+struct _GtkListStoreRow { | |
+ gpointer *data; /* Data for each column */ | |
+}; | |
+ | |
+struct _GtkListStore { | |
+ int ncols; /* Number of columns */ | |
+ int *coltype; /* Type of each column (e.g. G_TYPE_STRING) */ | |
+ GArray *rows; /* All rows in the list as GtkListStoreRow */ | |
+ GtkTreeView *view; /* The currently connected view (only one supported) */ | |
+}; | |
+ | |
+/* Empty struct; we don't support customizing the renderer */ | |
+struct _GtkCellRenderer { | |
+}; | |
+ | |
+typedef void (*GtkTreeSelectionForeachFunc) (GtkTreeModel *model, | |
+ GtkTreePath *path, GtkTreeIter *iter, gpointer data); | |
+ | |
+#define GTK_TREE_VIEW(obj) ((GtkTreeView *)(obj)) | |
+#define GTK_TREE_MODEL(obj) ((GtkTreeModel *)(obj)) | |
+#define GTK_LIST_STORE(obj) ((GtkListStore *)(obj)) | |
+ | |
+GtkListStore *gtk_list_store_new(gint n_columns, ...); | |
+void gtk_list_store_clear(GtkListStore *list_store); | |
+void gtk_list_store_insert(GtkListStore *list_store, GtkTreeIter *iter, | |
+ gint position); | |
+void gtk_list_store_append(GtkListStore *list_store, GtkTreeIter *iter); | |
+gboolean gtk_list_store_remove(GtkListStore *list_store, GtkTreeIter *iter); | |
+void gtk_list_store_set(GtkListStore *list_store, GtkTreeIter *iter, ...); | |
+ | |
+void gtk_tree_model_get(GtkTreeModel *tree_model, GtkTreeIter *iter, ...); | |
+ | |
+GtkWidget *gtk_tree_view_new(void); | |
+GtkTreeSelection *gtk_tree_view_get_selection(GtkTreeView *tree_view); | |
+void gtk_tree_view_set_model(GtkTreeView *tree_view, GtkTreeModel *model); | |
+GtkTreeModel *gtk_tree_view_get_model(GtkTreeView *tree_view); | |
+void gtk_tree_view_set_headers_clickable(GtkTreeView *tree_view, | |
+ gboolean setting); | |
+gint gtk_tree_view_insert_column_with_attributes | |
+ (GtkTreeView *tree_view, gint position, const gchar *title, | |
+ GtkCellRenderer *cell, ...); | |
+ | |
+void gtk_tree_selection_selected_foreach(GtkTreeSelection *selection, | |
+ GtkTreeSelectionForeachFunc func, | |
+ gpointer data); | |
+void gtk_tree_selection_set_mode(GtkTreeSelection *selection, | |
+ GtkSelectionMode type); | |
+gboolean gtk_tree_selection_get_selected(GtkTreeSelection *selection, | |
+ GtkTreeModel **model, | |
+ GtkTreeIter *iter); | |
+gint gtk_tree_selection_count_selected_rows(GtkTreeSelection *selection); | |
+void gtk_tree_selection_select_path(GtkTreeSelection *selection, | |
+ GtkTreePath *path); | |
+void gtk_tree_selection_unselect_path(GtkTreeSelection *selection, | |
+ GtkTreePath *path); | |
+ | |
+GtkTreeViewColumn *gtk_tree_view_column_new_with_attributes | |
+ (const gchar *title, GtkCellRenderer *cell, ...); | |
+void gtk_tree_view_column_set_resizable(GtkTreeViewColumn *tree_column, | |
+ gboolean resizable); | |
+void gtk_tree_view_column_set_expand(GtkTreeViewColumn *tree_column, | |
+ gboolean expand); | |
+gint gtk_tree_view_insert_column(GtkTreeView *tree_view, | |
+ GtkTreeViewColumn *column, | |
+ gint position); | |
+ | |
+GtkCellRenderer *gtk_cell_renderer_text_new(void); | |
+ | |
+GtkWidget *gtk_scrolled_tree_view_new(GtkWidget **pack_widg); | |
+ | |
+void g_object_unref(gpointer object); | |
+gpointer g_object_ref(gpointer object); | |
+ | |
+typedef void (*GCallback) (void); | |
+#define G_CALLBACK(f) ((GCallback) (f)) | |
+void g_signal_connect(gpointer instance, const char *signal, | |
+ GCallback handler, gpointer data); | |
+ | |
+/* Private functions */ | |
+void InitTreeViewClass(HINSTANCE hInstance); | |
+#endif /* CYGWIN */ | |
+ | |
+#endif | |
diff --git a/src/gui_client/newgamedia.c b/src/gui_client/newgamedia.c | |
t@@ -420,7 +420,7 @@ static GtkTreeModel *create_metaserver_model(void) | |
return GTK_TREE_MODEL(store); | |
} | |
-static GtkWidget *create_metaserver_view(void) | |
+static GtkWidget *create_metaserver_view(GtkWidget **pack_widg) | |
{ | |
int i; | |
GtkWidget *view; | |
t@@ -437,7 +437,7 @@ static GtkWidget *create_metaserver_view(void) | |
server_titles[3] = _("Players"); expand[3] = FALSE; | |
server_titles[4] = _("Comment"); expand[4] = TRUE; | |
- view = gtk_tree_view_new(); | |
+ view = gtk_scrolled_tree_view_new(pack_widg); | |
renderer = gtk_cell_renderer_text_new(); | |
for (i = 0; i < META_NUM_COLS; ++i) { | |
col = gtk_tree_view_column_new_with_attributes( | |
t@@ -605,15 +605,10 @@ void NewGameDialog(Player *play) | |
vbox2 = gtk_vbox_new(FALSE, 7); | |
gtk_container_set_border_width(GTK_CONTAINER(vbox2), 4); | |
- clist = stgam.metaserv = create_metaserver_view(); | |
+ clist = stgam.metaserv = create_metaserver_view(&scrollwin); | |
gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(clist), FALSE); | |
gtk_tree_selection_set_mode( | |
gtk_tree_view_get_selection(GTK_TREE_VIEW(clist)), GTK_SELECTION_SINGLE… | |
- scrollwin = gtk_scrolled_window_new(NULL, NULL); | |
- gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin), | |
- GTK_POLICY_AUTOMATIC, | |
- GTK_POLICY_AUTOMATIC); | |
- gtk_container_add (GTK_CONTAINER(scrollwin), clist); | |
gtk_box_pack_start(GTK_BOX(vbox2), scrollwin, TRUE, TRUE, 0); | |