forked from AuroraMiddleware/gtk
239a12d0d1
1998-03-09 Federico Mena Quintero <federico@nuclecu.unam.mx> * gtk/gtkclist.c (gtk_clist_set_foreground): We now accept the color parameter to be NULL. If it is NULL, it will mark the row with "color not set", so it will be repainted with the default color. (gtk_clist_set_background): Likewise.
3769 lines
92 KiB
C
3769 lines
92 KiB
C
/* GTK - The GIMP Toolkit
|
|
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball, Josh MacDonald,
|
|
* Copyright (C) 1997-1998 Jay Painter <jpaint@serv.net><jpaint@gimp.org>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library 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
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the Free
|
|
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
#include <stdlib.h>
|
|
#include "../config.h"
|
|
#include "gtkclist.h"
|
|
|
|
/* the number rows memchunk expands at a time */
|
|
#define CLIST_OPTIMUM_SIZE 512
|
|
|
|
/* the width of the column resize windows */
|
|
#define DRAG_WIDTH 6
|
|
|
|
/* minimum allowed width of a column */
|
|
#define COLUMN_MIN_WIDTH 5
|
|
|
|
/* this defigns the base grid spacing */
|
|
#define CELL_SPACING 1
|
|
|
|
/* added the horizontal space at the beginning and end of a row*/
|
|
#define COLUMN_INSET 3
|
|
|
|
/* scrollbar spacing class macro */
|
|
#define SCROLLBAR_SPACING(w) (GTK_CLIST_CLASS (GTK_OBJECT (w)->klass)->scrollbar_spacing)
|
|
|
|
/* gives the top pixel of the given row in context of
|
|
* the clist's voffset */
|
|
#define ROW_TOP_YPIXEL(clist, row) (((clist)->row_height * (row)) + \
|
|
(((row) + 1) * CELL_SPACING) + \
|
|
(clist)->voffset)
|
|
|
|
/* returns the row index from a y pixel location in the
|
|
* context of the clist's voffset */
|
|
#define ROW_FROM_YPIXEL(clist, y) (((y) - (clist)->voffset) / \
|
|
((clist)->row_height + CELL_SPACING))
|
|
|
|
/* gives the left pixel of the given column in context of
|
|
* the clist's hoffset */
|
|
#define COLUMN_LEFT_XPIXEL(clist, column) ((clist)->column[(column)].area.x + \
|
|
(clist)->hoffset)
|
|
|
|
/* returns the column index from a x pixel location in the
|
|
* context of the clist's hoffset */
|
|
static inline gint
|
|
COLUMN_FROM_XPIXEL (GtkCList * clist,
|
|
gint x)
|
|
{
|
|
gint i, cx;
|
|
|
|
for (i = 0; i < clist->columns; i++)
|
|
{
|
|
cx = clist->column[i].area.x + clist->hoffset;
|
|
|
|
if (x >= (cx - (COLUMN_INSET + CELL_SPACING)) &&
|
|
x <= (cx + clist->column[i].area.width + COLUMN_INSET))
|
|
return i;
|
|
}
|
|
|
|
/* no match */
|
|
return -1;
|
|
}
|
|
|
|
/* returns the top pixel of the given row in the context of
|
|
* the list height */
|
|
#define ROW_TOP(clist, row) (((clist)->row_height + CELL_SPACING) * (row))
|
|
|
|
/* returns the left pixel of the given column in the context of
|
|
* the list width */
|
|
#define COLUMN_LEFT(clist, column) ((clist)->column[(column)].area.x)
|
|
|
|
/* returns the total height of the list */
|
|
#define LIST_HEIGHT(clist) (((clist)->row_height * ((clist)->rows)) + \
|
|
(CELL_SPACING * ((clist)->rows + 1)))
|
|
|
|
/* returns the total width of the list */
|
|
#define LIST_WIDTH(clist) ((clist)->column[(clist)->columns - 1].area.x + \
|
|
(clist)->column[(clist)->columns - 1].area.width + \
|
|
COLUMN_INSET + CELL_SPACING)
|
|
|
|
|
|
/* Signals */
|
|
enum
|
|
{
|
|
SELECT_ROW,
|
|
UNSELECT_ROW,
|
|
CLICK_COLUMN,
|
|
LAST_SIGNAL
|
|
};
|
|
|
|
enum
|
|
{
|
|
SYNC_REMOVE,
|
|
SYNC_INSERT
|
|
};
|
|
|
|
|
|
typedef void (*GtkCListSignal1) (GtkObject * object,
|
|
gint arg1,
|
|
gint arg2,
|
|
GdkEventButton * arg3,
|
|
gpointer data);
|
|
|
|
typedef void (*GtkCListSignal2) (GtkObject * object,
|
|
gint arg1,
|
|
gpointer data);
|
|
|
|
|
|
static void sync_selection (GtkCList * clist,
|
|
gint row,
|
|
gint mode);
|
|
|
|
/* GtkCList Methods */
|
|
static void gtk_clist_class_init (GtkCListClass * klass);
|
|
static void gtk_clist_init (GtkCList * clist);
|
|
|
|
/* GtkObject Methods */
|
|
static void gtk_clist_destroy (GtkObject * object);
|
|
static void gtk_clist_finalize (GtkObject * object);
|
|
|
|
|
|
/* GtkWidget Methods */
|
|
static void gtk_clist_realize (GtkWidget * widget);
|
|
static void gtk_clist_unrealize (GtkWidget * widget);
|
|
static void gtk_clist_map (GtkWidget * widget);
|
|
static void gtk_clist_unmap (GtkWidget * widget);
|
|
static void gtk_clist_draw (GtkWidget * widget,
|
|
GdkRectangle * area);
|
|
static gint gtk_clist_expose (GtkWidget * widget,
|
|
GdkEventExpose * event);
|
|
static gint gtk_clist_button_press (GtkWidget * widget,
|
|
GdkEventButton * event);
|
|
static gint gtk_clist_button_release (GtkWidget * widget,
|
|
GdkEventButton * event);
|
|
static gint gtk_clist_motion (GtkWidget * widget,
|
|
GdkEventMotion * event);
|
|
|
|
static void gtk_clist_size_request (GtkWidget * widget,
|
|
GtkRequisition * requisition);
|
|
static void gtk_clist_size_allocate (GtkWidget * widget,
|
|
GtkAllocation * allocation);
|
|
|
|
/* GtkContainer Methods */
|
|
static void gtk_clist_foreach (GtkContainer * container,
|
|
GtkCallback callback,
|
|
gpointer callback_data);
|
|
|
|
/* Drawing */
|
|
static void draw_row (GtkCList * clist,
|
|
GdkRectangle * area,
|
|
gint row,
|
|
GtkCListRow * clist_row);
|
|
static void draw_rows (GtkCList * clist,
|
|
GdkRectangle * area);
|
|
|
|
/* Size Allocation */
|
|
static void size_allocate_title_buttons (GtkCList * clist);
|
|
static void size_allocate_columns (GtkCList * clist);
|
|
|
|
/* Selection */
|
|
static void toggle_row (GtkCList * clist,
|
|
gint row,
|
|
gint column,
|
|
GdkEventButton * event);
|
|
static void select_row (GtkCList * clist,
|
|
gint row,
|
|
gint column,
|
|
GdkEventButton * event);
|
|
static void unselect_row (GtkCList * clist,
|
|
gint row,
|
|
gint column,
|
|
GdkEventButton * event);
|
|
|
|
static void real_select_row (GtkCList * clist,
|
|
gint row,
|
|
gint column,
|
|
GdkEventButton * event);
|
|
static void real_unselect_row (GtkCList * clist,
|
|
gint row,
|
|
gint column,
|
|
GdkEventButton * event);
|
|
|
|
static gint get_selection_info (GtkCList * clist,
|
|
gint x,
|
|
gint y,
|
|
gint * row,
|
|
gint * column);
|
|
|
|
/* Resize Columns */
|
|
static void draw_xor_line (GtkCList * clist);
|
|
static gint new_column_width (GtkCList * clist,
|
|
gint column,
|
|
gint * x,
|
|
gint * visible);
|
|
static void resize_column (GtkCList * clist,
|
|
gint column,
|
|
gint width);
|
|
|
|
/* Buttons */
|
|
static void column_button_create (GtkCList * clist,
|
|
gint column);
|
|
static void column_button_clicked (GtkWidget * widget,
|
|
gpointer data);
|
|
|
|
/* Scrollbars */
|
|
static void create_scrollbars (GtkCList * clist);
|
|
static void adjust_scrollbars (GtkCList * clist);
|
|
static void check_exposures (GtkCList * clist);
|
|
static void vadjustment_changed (GtkAdjustment * adjustment,
|
|
gpointer data);
|
|
static void vadjustment_value_changed (GtkAdjustment * adjustment,
|
|
gpointer data);
|
|
static void hadjustment_changed (GtkAdjustment * adjustment,
|
|
gpointer data);
|
|
static void hadjustment_value_changed (GtkAdjustment * adjustment,
|
|
gpointer data);
|
|
|
|
|
|
/* Memory Allocation/Distruction Routines */
|
|
static GtkCListColumn *columns_new (GtkCList * clist);
|
|
|
|
static void column_title_new (GtkCList * clist,
|
|
gint column,
|
|
gchar * title);
|
|
static void columns_delete (GtkCList * clist);
|
|
|
|
static GtkCListRow *row_new (GtkCList * clist);
|
|
|
|
static void row_delete (GtkCList * clist,
|
|
GtkCListRow * clist_row);
|
|
static void cell_empty (GtkCList * clist,
|
|
GtkCListRow * clist_row,
|
|
gint column);
|
|
static void cell_set_text (GtkCList * clist,
|
|
GtkCListRow * clist_row,
|
|
gint column,
|
|
gchar * text);
|
|
static void cell_set_pixmap (GtkCList * clist,
|
|
GtkCListRow * clist_row,
|
|
gint column,
|
|
GdkPixmap * pixmap,
|
|
GdkBitmap * mask);
|
|
static void cell_set_pixtext (GtkCList * clist,
|
|
GtkCListRow * clist_row,
|
|
gint column,
|
|
gchar * text,
|
|
guint8 spacing,
|
|
GdkPixmap * pixmap,
|
|
GdkBitmap * mask);
|
|
|
|
/* Signals */
|
|
static void gtk_clist_marshal_signal_1 (GtkObject * object,
|
|
GtkSignalFunc func,
|
|
gpointer func_data,
|
|
GtkArg * args);
|
|
static void gtk_clist_marshal_signal_2 (GtkObject * object,
|
|
GtkSignalFunc func,
|
|
gpointer func_data,
|
|
GtkArg * args);
|
|
|
|
/* Fill in data after widget is realized and has style */
|
|
|
|
static void add_style_data (GtkCList * clist);
|
|
|
|
static GtkContainerClass *parent_class = NULL;
|
|
static guint clist_signals[LAST_SIGNAL] = {0};
|
|
|
|
|
|
guint
|
|
gtk_clist_get_type ()
|
|
{
|
|
static guint clist_type = 0;
|
|
|
|
if (!clist_type)
|
|
{
|
|
GtkTypeInfo clist_info =
|
|
{
|
|
"GtkCList",
|
|
sizeof (GtkCList),
|
|
sizeof (GtkCListClass),
|
|
(GtkClassInitFunc) gtk_clist_class_init,
|
|
(GtkObjectInitFunc) gtk_clist_init,
|
|
(GtkArgSetFunc) NULL,
|
|
(GtkArgGetFunc) NULL,
|
|
};
|
|
|
|
clist_type = gtk_type_unique (gtk_container_get_type (), &clist_info);
|
|
}
|
|
|
|
return clist_type;
|
|
}
|
|
|
|
static void
|
|
gtk_clist_class_init (GtkCListClass * klass)
|
|
{
|
|
GtkObjectClass *object_class;
|
|
GtkWidgetClass *widget_class;
|
|
GtkContainerClass *container_class;
|
|
|
|
object_class = (GtkObjectClass *) klass;
|
|
widget_class = (GtkWidgetClass *) klass;
|
|
container_class = (GtkContainerClass *) klass;
|
|
|
|
parent_class = gtk_type_class (gtk_container_get_type ());
|
|
|
|
clist_signals[SELECT_ROW] =
|
|
gtk_signal_new ("select_row",
|
|
GTK_RUN_FIRST,
|
|
object_class->type,
|
|
GTK_SIGNAL_OFFSET (GtkCListClass, select_row),
|
|
gtk_clist_marshal_signal_1,
|
|
GTK_TYPE_NONE, 3, GTK_TYPE_INT, GTK_TYPE_INT, GTK_TYPE_POINTER);
|
|
clist_signals[UNSELECT_ROW] =
|
|
gtk_signal_new ("unselect_row",
|
|
GTK_RUN_FIRST,
|
|
object_class->type,
|
|
GTK_SIGNAL_OFFSET (GtkCListClass, unselect_row),
|
|
gtk_clist_marshal_signal_1,
|
|
GTK_TYPE_NONE, 3, GTK_TYPE_INT, GTK_TYPE_INT, GTK_TYPE_POINTER);
|
|
clist_signals[CLICK_COLUMN] =
|
|
gtk_signal_new ("click_column",
|
|
GTK_RUN_FIRST,
|
|
object_class->type,
|
|
GTK_SIGNAL_OFFSET (GtkCListClass, click_column),
|
|
gtk_clist_marshal_signal_2,
|
|
GTK_TYPE_NONE, 1, GTK_TYPE_INT);
|
|
|
|
gtk_object_class_add_signals (object_class, clist_signals, LAST_SIGNAL);
|
|
|
|
object_class->destroy = gtk_clist_destroy;
|
|
object_class->finalize = gtk_clist_finalize;
|
|
|
|
widget_class->realize = gtk_clist_realize;
|
|
widget_class->unrealize = gtk_clist_unrealize;
|
|
widget_class->map = gtk_clist_map;
|
|
widget_class->unmap = gtk_clist_unmap;
|
|
widget_class->draw = gtk_clist_draw;
|
|
widget_class->button_press_event = gtk_clist_button_press;
|
|
widget_class->button_release_event = gtk_clist_button_release;
|
|
widget_class->motion_notify_event = gtk_clist_motion;
|
|
widget_class->expose_event = gtk_clist_expose;
|
|
widget_class->size_request = gtk_clist_size_request;
|
|
widget_class->size_allocate = gtk_clist_size_allocate;
|
|
|
|
container_class->add = NULL;
|
|
container_class->remove = NULL;
|
|
container_class->foreach = gtk_clist_foreach;
|
|
|
|
klass->select_row = real_select_row;
|
|
klass->unselect_row = real_unselect_row;
|
|
klass->click_column = NULL;
|
|
|
|
klass->scrollbar_spacing = 5;
|
|
}
|
|
|
|
static void
|
|
gtk_clist_marshal_signal_1 (GtkObject * object,
|
|
GtkSignalFunc func,
|
|
gpointer func_data,
|
|
GtkArg * args)
|
|
{
|
|
GtkCListSignal1 rfunc;
|
|
|
|
rfunc = (GtkCListSignal1) func;
|
|
|
|
(*rfunc) (object, GTK_VALUE_INT (args[0]),
|
|
GTK_VALUE_INT (args[1]),
|
|
GTK_VALUE_POINTER (args[2]),
|
|
func_data);
|
|
}
|
|
|
|
static void
|
|
gtk_clist_marshal_signal_2 (GtkObject * object,
|
|
GtkSignalFunc func,
|
|
gpointer func_data,
|
|
GtkArg * args)
|
|
{
|
|
GtkCListSignal2 rfunc;
|
|
|
|
rfunc = (GtkCListSignal2) func;
|
|
|
|
(*rfunc) (object, GTK_VALUE_INT (args[0]),
|
|
func_data);
|
|
}
|
|
|
|
static void
|
|
gtk_clist_init (GtkCList * clist)
|
|
{
|
|
clist->flags = 0;
|
|
|
|
GTK_WIDGET_UNSET_FLAGS (clist, GTK_NO_WINDOW);
|
|
GTK_CLIST_SET_FLAGS (clist, CLIST_FROZEN);
|
|
|
|
clist->row_mem_chunk = NULL;
|
|
clist->cell_mem_chunk = NULL;
|
|
|
|
clist->rows = 0;
|
|
clist->row_center_offset = 0;
|
|
clist->row_height = 0;
|
|
clist->row_list = NULL;
|
|
clist->row_list_end = NULL;
|
|
|
|
clist->columns = 0;
|
|
|
|
clist->title_window = NULL;
|
|
clist->column_title_area.x = 0;
|
|
clist->column_title_area.y = 0;
|
|
clist->column_title_area.width = 0;
|
|
clist->column_title_area.height = 0;
|
|
|
|
clist->clist_window = NULL;
|
|
clist->clist_window_width = 0;
|
|
clist->clist_window_height = 0;
|
|
|
|
clist->hoffset = 0;
|
|
clist->voffset = 0;
|
|
|
|
clist->shadow_type = GTK_SHADOW_IN;
|
|
clist->hscrollbar_policy = GTK_POLICY_ALWAYS;
|
|
clist->vscrollbar_policy = GTK_POLICY_ALWAYS;
|
|
|
|
clist->cursor_drag = NULL;
|
|
clist->xor_gc = NULL;
|
|
clist->fg_gc = NULL;
|
|
clist->bg_gc = NULL;
|
|
clist->x_drag = 0;
|
|
|
|
clist->selection_mode = GTK_SELECTION_SINGLE;
|
|
clist->selection = NULL;
|
|
}
|
|
|
|
/* Constructors */
|
|
void
|
|
gtk_clist_construct (GtkCList * clist,
|
|
gint columns,
|
|
gchar *titles[])
|
|
{
|
|
int i;
|
|
|
|
g_return_if_fail (clist != NULL);
|
|
g_return_if_fail (GTK_IS_CLIST (clist));
|
|
g_return_if_fail (clist->row_mem_chunk == NULL);
|
|
|
|
|
|
/* initalize memory chunks */
|
|
clist->row_mem_chunk = g_mem_chunk_new ("clist row mem chunk",
|
|
sizeof (GtkCListRow),
|
|
sizeof (GtkCListRow) * CLIST_OPTIMUM_SIZE,
|
|
G_ALLOC_AND_FREE);
|
|
|
|
clist->cell_mem_chunk = g_mem_chunk_new ("clist cell mem chunk",
|
|
sizeof (GtkCell) * columns,
|
|
sizeof (GtkCell) * columns * CLIST_OPTIMUM_SIZE,
|
|
G_ALLOC_AND_FREE);
|
|
|
|
/* set number of columns, allocate memory */
|
|
clist->columns = columns;
|
|
clist->column = columns_new (clist);
|
|
|
|
/* there needs to be at least one column button
|
|
* because there is alot of code that will break if it
|
|
* isn't there*/
|
|
column_button_create (clist, 0);
|
|
|
|
/* create scrollbars */
|
|
create_scrollbars (clist);
|
|
|
|
if (titles)
|
|
{
|
|
GTK_CLIST_SET_FLAGS (clist, CLIST_SHOW_TITLES);
|
|
for (i = 0; i < columns; i++)
|
|
gtk_clist_set_column_title (clist, i, titles[i]);
|
|
}
|
|
else
|
|
{
|
|
GTK_CLIST_UNSET_FLAGS (clist, CLIST_SHOW_TITLES);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* GTKCLIST PUBLIC INTERFACE
|
|
* gtk_clist_new_with_titles
|
|
* gtk_clist_new
|
|
*/
|
|
GtkWidget *
|
|
gtk_clist_new_with_titles (gint columns,
|
|
gchar * titles[])
|
|
{
|
|
GtkWidget *widget;
|
|
|
|
g_return_val_if_fail (titles != NULL, NULL);
|
|
|
|
widget = gtk_type_new (gtk_clist_get_type ());
|
|
|
|
gtk_clist_construct (GTK_CLIST (widget), columns, titles);
|
|
|
|
return widget;
|
|
}
|
|
|
|
GtkWidget *
|
|
gtk_clist_new (gint columns)
|
|
{
|
|
GtkCList *clist;
|
|
|
|
if (columns < 1)
|
|
return NULL;
|
|
|
|
clist = gtk_type_new (gtk_clist_get_type ());
|
|
gtk_clist_construct (clist, columns, NULL);
|
|
return GTK_WIDGET (clist);
|
|
}
|
|
|
|
void
|
|
gtk_clist_set_border (GtkCList * clist,
|
|
GtkShadowType border)
|
|
{
|
|
g_return_if_fail (clist != NULL);
|
|
|
|
clist->shadow_type = border;
|
|
|
|
if (GTK_WIDGET_VISIBLE (clist))
|
|
gtk_widget_queue_resize (GTK_WIDGET (clist));
|
|
}
|
|
|
|
void
|
|
gtk_clist_set_selection_mode (GtkCList * clist,
|
|
GtkSelectionMode mode)
|
|
{
|
|
g_return_if_fail (clist != NULL);
|
|
|
|
clist->selection_mode = mode;
|
|
}
|
|
|
|
void
|
|
gtk_clist_freeze (GtkCList * clist)
|
|
{
|
|
g_return_if_fail (clist != NULL);
|
|
|
|
GTK_CLIST_SET_FLAGS (clist, CLIST_FROZEN);
|
|
}
|
|
|
|
void
|
|
gtk_clist_thaw (GtkCList * clist)
|
|
{
|
|
g_return_if_fail (clist != NULL);
|
|
|
|
GTK_CLIST_UNSET_FLAGS (clist, CLIST_FROZEN);
|
|
|
|
adjust_scrollbars (clist);
|
|
draw_rows (clist, NULL);
|
|
}
|
|
|
|
void
|
|
gtk_clist_column_titles_show (GtkCList * clist)
|
|
{
|
|
g_return_if_fail (clist != NULL);
|
|
|
|
if (!GTK_CLIST_SHOW_TITLES (clist))
|
|
{
|
|
GTK_CLIST_SET_FLAGS (clist, CLIST_SHOW_TITLES);
|
|
gdk_window_show (clist->title_window);
|
|
gtk_widget_queue_resize (GTK_WIDGET (clist));
|
|
}
|
|
}
|
|
|
|
void
|
|
gtk_clist_column_titles_hide (GtkCList * clist)
|
|
{
|
|
g_return_if_fail (clist != NULL);
|
|
|
|
if (GTK_CLIST_SHOW_TITLES (clist))
|
|
{
|
|
GTK_CLIST_UNSET_FLAGS (clist, CLIST_SHOW_TITLES);
|
|
gdk_window_hide (clist->title_window);
|
|
gtk_widget_queue_resize (GTK_WIDGET (clist));
|
|
}
|
|
}
|
|
|
|
void
|
|
gtk_clist_column_title_active (GtkCList * clist,
|
|
gint column)
|
|
{
|
|
g_return_if_fail (clist != NULL);
|
|
|
|
if (column < 0 || column >= clist->columns)
|
|
return;
|
|
|
|
if (!GTK_WIDGET_SENSITIVE (clist->column[column].button) ||
|
|
!GTK_WIDGET_CAN_FOCUS (clist->column[column].button))
|
|
{
|
|
GTK_WIDGET_SET_FLAGS (clist->column[column].button, GTK_SENSITIVE | GTK_CAN_FOCUS);
|
|
if (GTK_WIDGET_VISIBLE (clist))
|
|
gtk_widget_queue_draw (clist->column[column].button);
|
|
}
|
|
}
|
|
|
|
void
|
|
gtk_clist_column_title_passive (GtkCList * clist,
|
|
gint column)
|
|
{
|
|
g_return_if_fail (clist != NULL);
|
|
|
|
if (column < 0 || column >= clist->columns)
|
|
return;
|
|
|
|
if (GTK_WIDGET_SENSITIVE (clist->column[column].button) ||
|
|
GTK_WIDGET_CAN_FOCUS (clist->column[column].button))
|
|
{
|
|
GTK_WIDGET_UNSET_FLAGS (clist->column[column].button, GTK_SENSITIVE | GTK_CAN_FOCUS);
|
|
if (GTK_WIDGET_VISIBLE (clist))
|
|
gtk_widget_queue_draw (clist->column[column].button);
|
|
}
|
|
}
|
|
|
|
void
|
|
gtk_clist_column_titles_active (GtkCList * clist)
|
|
{
|
|
gint i;
|
|
|
|
g_return_if_fail (clist != NULL);
|
|
|
|
for (i = 0; i < clist->columns; i++)
|
|
if (clist->column[i].button)
|
|
gtk_clist_column_title_active (clist, i);
|
|
}
|
|
|
|
void
|
|
gtk_clist_column_titles_passive (GtkCList * clist)
|
|
{
|
|
gint i;
|
|
|
|
g_return_if_fail (clist != NULL);
|
|
|
|
for (i = 0; i < clist->columns; i++)
|
|
if (clist->column[i].button)
|
|
gtk_clist_column_title_passive (clist, i);
|
|
}
|
|
|
|
void
|
|
gtk_clist_set_column_title (GtkCList * clist,
|
|
gint column,
|
|
gchar * title)
|
|
{
|
|
gint new_button = 0;
|
|
GtkWidget *old_widget;
|
|
GtkWidget *alignment = NULL;
|
|
GtkWidget *label;
|
|
|
|
g_return_if_fail (clist != NULL);
|
|
|
|
if (column < 0 || column >= clist->columns)
|
|
return;
|
|
|
|
/* if the column button doesn't currently exist,
|
|
* it has to be created first */
|
|
if (!clist->column[column].button)
|
|
{
|
|
column_button_create (clist, column);
|
|
new_button = 1;
|
|
}
|
|
|
|
column_title_new (clist, column, title);
|
|
|
|
/* remove and destroy the old widget */
|
|
old_widget = GTK_BUTTON (clist->column[column].button)->child;
|
|
if (old_widget)
|
|
{
|
|
gtk_container_remove (GTK_CONTAINER (clist->column[column].button), old_widget);
|
|
gtk_widget_destroy (old_widget);
|
|
}
|
|
|
|
/* create new alignment based no column justification */
|
|
switch (clist->column[column].justification)
|
|
{
|
|
case GTK_JUSTIFY_LEFT:
|
|
alignment = gtk_alignment_new (0.0, 0.5, 0.0, 0.0);
|
|
break;
|
|
|
|
case GTK_JUSTIFY_RIGHT:
|
|
alignment = gtk_alignment_new (1.0, 0.5, 0.0, 0.0);
|
|
break;
|
|
|
|
case GTK_JUSTIFY_CENTER:
|
|
alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
|
|
break;
|
|
|
|
case GTK_JUSTIFY_FILL:
|
|
alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
|
|
break;
|
|
}
|
|
|
|
label = gtk_label_new (clist->column[column].title);
|
|
gtk_container_add (GTK_CONTAINER (alignment), label);
|
|
gtk_container_add (GTK_CONTAINER (clist->column[column].button), alignment);
|
|
gtk_widget_show (label);
|
|
gtk_widget_show (alignment);
|
|
|
|
/* if this button didn't previously exist, then the
|
|
* column button positions have to be re-computed */
|
|
if (GTK_WIDGET_VISIBLE (clist) && new_button)
|
|
size_allocate_title_buttons (clist);
|
|
}
|
|
|
|
void
|
|
gtk_clist_set_column_widget (GtkCList * clist,
|
|
gint column,
|
|
GtkWidget * widget)
|
|
{
|
|
gint new_button = 0;
|
|
GtkWidget *old_widget;
|
|
|
|
g_return_if_fail (clist != NULL);
|
|
|
|
if (column < 0 || column >= clist->columns)
|
|
return;
|
|
|
|
/* if the column button doesn't currently exist,
|
|
* it has to be created first */
|
|
if (!clist->column[column].button)
|
|
{
|
|
column_button_create (clist, column);
|
|
new_button = 1;
|
|
}
|
|
|
|
column_title_new (clist, column, NULL);
|
|
|
|
/* remove and destroy the old widget */
|
|
old_widget = GTK_BUTTON (clist->column[column].button)->child;
|
|
if (old_widget)
|
|
{
|
|
gtk_container_remove (GTK_CONTAINER (clist->column[column].button), old_widget);
|
|
gtk_widget_destroy (old_widget);
|
|
}
|
|
|
|
/* add and show the widget */
|
|
if (widget)
|
|
{
|
|
gtk_container_add (GTK_CONTAINER (clist->column[column].button), widget);
|
|
gtk_widget_show (widget);
|
|
}
|
|
|
|
/* if this button didn't previously exist, then the
|
|
* column button positions have to be re-computed */
|
|
if (GTK_WIDGET_VISIBLE (clist) && new_button)
|
|
size_allocate_title_buttons (clist);
|
|
}
|
|
|
|
void
|
|
gtk_clist_set_column_justification (GtkCList * clist,
|
|
gint column,
|
|
GtkJustification justification)
|
|
{
|
|
GtkWidget *alignment;
|
|
|
|
g_return_if_fail (clist != NULL);
|
|
|
|
if (column < 0 || column >= clist->columns)
|
|
return;
|
|
|
|
clist->column[column].justification = justification;
|
|
|
|
/* change the alinment of the button title if it's not a
|
|
* custom widget */
|
|
if (clist->column[column].title)
|
|
{
|
|
alignment = GTK_BUTTON (clist->column[column].button)->child;
|
|
|
|
switch (clist->column[column].justification)
|
|
{
|
|
case GTK_JUSTIFY_LEFT:
|
|
gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.0, 0.5, 0.0, 0.0);
|
|
break;
|
|
|
|
case GTK_JUSTIFY_RIGHT:
|
|
gtk_alignment_set (GTK_ALIGNMENT (alignment), 1.0, 0.5, 0.0, 0.0);
|
|
break;
|
|
|
|
case GTK_JUSTIFY_CENTER:
|
|
gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.5, 0.5, 0.0, 0.0);
|
|
break;
|
|
|
|
case GTK_JUSTIFY_FILL:
|
|
gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.5, 0.5, 0.0, 0.0);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!GTK_CLIST_FROZEN (clist))
|
|
draw_rows (clist, NULL);
|
|
}
|
|
|
|
void
|
|
gtk_clist_set_column_width (GtkCList * clist,
|
|
gint column,
|
|
gint width)
|
|
{
|
|
g_return_if_fail (clist != NULL);
|
|
|
|
if (column < 0 || column >= clist->columns)
|
|
return;
|
|
|
|
clist->column[column].width = width;
|
|
clist->column[column].width_set = TRUE;
|
|
|
|
/* FIXME: this is quite expensive to do if the widget hasn't
|
|
* been size_allocated yet, and pointless. Should
|
|
* a flag be kept
|
|
*/
|
|
size_allocate_columns (clist);
|
|
size_allocate_title_buttons (clist);
|
|
|
|
if (!GTK_CLIST_FROZEN (clist))
|
|
{
|
|
adjust_scrollbars (clist);
|
|
draw_rows (clist, NULL);
|
|
}
|
|
}
|
|
|
|
void
|
|
gtk_clist_set_row_height (GtkCList * clist,
|
|
gint height)
|
|
{
|
|
gint text_height;
|
|
|
|
g_return_if_fail (clist != NULL);
|
|
|
|
if (height > 0)
|
|
clist->row_height = height;
|
|
else
|
|
return;
|
|
|
|
GTK_CLIST_SET_FLAGS (clist, CLIST_ROW_HEIGHT_SET);
|
|
|
|
if (GTK_WIDGET_REALIZED (clist))
|
|
{
|
|
text_height = height - (GTK_WIDGET (clist)->style->font->ascent +
|
|
GTK_WIDGET (clist) ->style->font->descent + 1);
|
|
clist->row_center_offset = (text_height / 2) + GTK_WIDGET (clist)->style->font->ascent + 1.5;
|
|
}
|
|
|
|
if (!GTK_CLIST_FROZEN (clist))
|
|
{
|
|
adjust_scrollbars (clist);
|
|
draw_rows (clist, NULL);
|
|
}
|
|
}
|
|
|
|
void
|
|
gtk_clist_moveto (GtkCList * clist,
|
|
gint row,
|
|
gint column,
|
|
gfloat row_align,
|
|
gfloat col_align)
|
|
{
|
|
gint x, y;
|
|
|
|
g_return_if_fail (clist != NULL);
|
|
|
|
if (row < -1 || row >= clist->rows)
|
|
return;
|
|
if (column < -1 || column >= clist->columns)
|
|
return;
|
|
|
|
/* adjust vertical scrollbar */
|
|
if (row >= 0)
|
|
{
|
|
x = ROW_TOP (clist, row) - (row_align * (clist->clist_window_height -
|
|
(clist->row_height + 2 * CELL_SPACING)));
|
|
|
|
if (x < 0)
|
|
GTK_RANGE (clist->vscrollbar)->adjustment->value = 0.0;
|
|
else if (x > LIST_HEIGHT (clist) - clist->clist_window_height)
|
|
GTK_RANGE (clist->vscrollbar)->adjustment->value = LIST_HEIGHT (clist) -
|
|
clist->clist_window_height;
|
|
else
|
|
GTK_RANGE (clist->vscrollbar)->adjustment->value = x;
|
|
|
|
gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment),
|
|
"value_changed");
|
|
}
|
|
|
|
/* adjust horizontal scrollbar */
|
|
if (column >= 0)
|
|
{
|
|
y = COLUMN_LEFT (clist, column) - (col_align * (clist->clist_window_width -
|
|
clist->column[column].area.width +
|
|
2 * (CELL_SPACING + COLUMN_INSET)));
|
|
|
|
if (y < 0)
|
|
GTK_RANGE (clist->hscrollbar)->adjustment->value = 0.0;
|
|
else if (y > LIST_WIDTH (clist) - clist->clist_window_width)
|
|
GTK_RANGE (clist->hscrollbar)->adjustment->value = LIST_WIDTH (clist) -
|
|
clist->clist_window_width;
|
|
else
|
|
GTK_RANGE (clist->hscrollbar)->adjustment->value = y;
|
|
|
|
gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->hscrollbar)->adjustment),
|
|
"value_changed");
|
|
}
|
|
}
|
|
|
|
GtkCellType
|
|
gtk_clist_get_cell_type (GtkCList * clist,
|
|
gint row,
|
|
gint column)
|
|
{
|
|
GtkCListRow *clist_row;
|
|
|
|
g_return_val_if_fail (clist != NULL, -1);
|
|
|
|
if (row < 0 || row >= clist->rows)
|
|
return -1;
|
|
if (column < 0 || column >= clist->columns)
|
|
return -1;
|
|
|
|
clist_row = (g_list_nth (clist->row_list, row))->data;
|
|
|
|
return clist_row->cell[column].type;
|
|
}
|
|
|
|
void
|
|
gtk_clist_set_text (GtkCList * clist,
|
|
gint row,
|
|
gint column,
|
|
gchar * text)
|
|
{
|
|
GtkCListRow *clist_row;
|
|
|
|
g_return_if_fail (clist != NULL);
|
|
|
|
if (row < 0 || row >= clist->rows)
|
|
return;
|
|
if (column < 0 || column >= clist->columns)
|
|
return;
|
|
|
|
clist_row = (g_list_nth (clist->row_list, row))->data;
|
|
|
|
/* if text is null, then the cell is empty */
|
|
if (text)
|
|
cell_set_text (clist, clist_row, column, text);
|
|
else
|
|
cell_empty (clist, clist_row, column);
|
|
|
|
/* redraw the list if it's not frozen */
|
|
if (!GTK_CLIST_FROZEN (clist))
|
|
{
|
|
if (gtk_clist_row_is_visible (clist, row))
|
|
draw_row (clist, NULL, row, clist_row);
|
|
}
|
|
}
|
|
|
|
gint
|
|
gtk_clist_get_text (GtkCList * clist,
|
|
gint row,
|
|
gint column,
|
|
gchar ** text)
|
|
{
|
|
GtkCListRow *clist_row;
|
|
|
|
g_return_val_if_fail (clist != NULL, 0);
|
|
|
|
if (row < 0 || row >= clist->rows)
|
|
return 0;
|
|
if (column < 0 || column >= clist->columns)
|
|
return 0;
|
|
|
|
clist_row = (g_list_nth (clist->row_list, row))->data;
|
|
|
|
if (clist_row->cell[column].type != GTK_CELL_TEXT)
|
|
return 0;
|
|
|
|
if (text)
|
|
*text = GTK_CELL_TEXT (clist_row->cell[column])->text;
|
|
|
|
return 1;
|
|
}
|
|
|
|
void
|
|
gtk_clist_set_pixmap (GtkCList * clist,
|
|
gint row,
|
|
gint column,
|
|
GdkPixmap * pixmap,
|
|
GdkBitmap * mask)
|
|
{
|
|
GtkCListRow *clist_row;
|
|
|
|
g_return_if_fail (clist != NULL);
|
|
|
|
if (row < 0 || row >= clist->rows)
|
|
return;
|
|
if (column < 0 || column >= clist->columns)
|
|
return;
|
|
|
|
clist_row = (g_list_nth (clist->row_list, row))->data;
|
|
|
|
gdk_pixmap_ref (pixmap);
|
|
|
|
if (mask) gdk_pixmap_ref (mask);
|
|
|
|
cell_set_pixmap (clist, clist_row, column, pixmap, mask);
|
|
|
|
/* redraw the list if it's not frozen */
|
|
if (!GTK_CLIST_FROZEN (clist))
|
|
{
|
|
if (gtk_clist_row_is_visible (clist, row))
|
|
draw_row (clist, NULL, row, clist_row);
|
|
}
|
|
}
|
|
|
|
gint
|
|
gtk_clist_get_pixmap (GtkCList * clist,
|
|
gint row,
|
|
gint column,
|
|
GdkPixmap ** pixmap,
|
|
GdkBitmap ** mask)
|
|
{
|
|
GtkCListRow *clist_row;
|
|
|
|
g_return_val_if_fail (clist != NULL, 0);
|
|
|
|
if (row < 0 || row >= clist->rows)
|
|
return 0;
|
|
if (column < 0 || column >= clist->columns)
|
|
return 0;
|
|
|
|
clist_row = (g_list_nth (clist->row_list, row))->data;
|
|
|
|
if (clist_row->cell[column].type != GTK_CELL_PIXMAP)
|
|
return 0;
|
|
|
|
if (pixmap)
|
|
{
|
|
*pixmap = GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap;
|
|
/* mask can be NULL */
|
|
*mask = GTK_CELL_PIXMAP (clist_row->cell[column])->mask;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
void
|
|
gtk_clist_set_pixtext (GtkCList * clist,
|
|
gint row,
|
|
gint column,
|
|
gchar * text,
|
|
guint8 spacing,
|
|
GdkPixmap * pixmap,
|
|
GdkBitmap * mask)
|
|
{
|
|
GtkCListRow *clist_row;
|
|
|
|
g_return_if_fail (clist != NULL);
|
|
|
|
if (row < 0 || row >= clist->rows)
|
|
return;
|
|
if (column < 0 || column >= clist->columns)
|
|
return;
|
|
|
|
clist_row = (g_list_nth (clist->row_list, row))->data;
|
|
|
|
gdk_pixmap_ref (pixmap);
|
|
if (mask) gdk_pixmap_ref (mask);
|
|
cell_set_pixtext (clist, clist_row, column, text, spacing, pixmap, mask);
|
|
|
|
/* redraw the list if it's not frozen */
|
|
if (!GTK_CLIST_FROZEN (clist))
|
|
{
|
|
if (gtk_clist_row_is_visible (clist, row))
|
|
draw_row (clist, NULL, row, clist_row);
|
|
}
|
|
}
|
|
|
|
gint
|
|
gtk_clist_get_pixtext (GtkCList * clist,
|
|
gint row,
|
|
gint column,
|
|
gchar ** text,
|
|
guint8 * spacing,
|
|
GdkPixmap ** pixmap,
|
|
GdkBitmap ** mask)
|
|
{
|
|
GtkCListRow *clist_row;
|
|
|
|
g_return_val_if_fail (clist != NULL, 0);
|
|
|
|
if (row < 0 || row >= clist->rows)
|
|
return 0;
|
|
if (column < 0 || column >= clist->columns)
|
|
return 0;
|
|
|
|
clist_row = (g_list_nth (clist->row_list, row))->data;
|
|
|
|
if (clist_row->cell[column].type != GTK_CELL_PIXTEXT)
|
|
return 0;
|
|
|
|
if (text)
|
|
*text = GTK_CELL_PIXTEXT (clist_row->cell[column])->text;
|
|
if (spacing)
|
|
*spacing = GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing;
|
|
if (pixmap)
|
|
*pixmap = GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap;
|
|
|
|
/* mask can be NULL */
|
|
*mask = GTK_CELL_PIXTEXT (clist_row->cell[column])->mask;
|
|
|
|
return 1;
|
|
}
|
|
|
|
void
|
|
gtk_clist_set_foreground (GtkCList * clist,
|
|
gint row,
|
|
GdkColor * color)
|
|
{
|
|
GtkCListRow *clist_row;
|
|
|
|
g_return_if_fail (clist != NULL);
|
|
|
|
if (row < 0 || row >= clist->rows)
|
|
return;
|
|
|
|
clist_row = (g_list_nth (clist->row_list, row))->data;
|
|
|
|
if (color)
|
|
{
|
|
clist_row->foreground = *color;
|
|
clist_row->fg_set = TRUE;
|
|
}
|
|
else
|
|
clist_row->fg_set = FALSE;
|
|
|
|
if (!GTK_CLIST_FROZEN (clist) && gtk_clist_row_is_visible (clist, row))
|
|
draw_row (clist, NULL, row, clist_row);
|
|
}
|
|
|
|
void
|
|
gtk_clist_set_background (GtkCList * clist,
|
|
gint row,
|
|
GdkColor * color)
|
|
{
|
|
GtkCListRow *clist_row;
|
|
|
|
g_return_if_fail (clist != NULL);
|
|
|
|
if (row < 0 || row >= clist->rows)
|
|
return;
|
|
|
|
clist_row = (g_list_nth (clist->row_list, row))->data;
|
|
|
|
if (color)
|
|
{
|
|
clist_row->background = *color;
|
|
clist_row->bg_set = TRUE;
|
|
}
|
|
else
|
|
clist_row->bg_set = FALSE;
|
|
|
|
if (!GTK_CLIST_FROZEN (clist) && gtk_clist_row_is_visible (clist, row))
|
|
draw_row (clist, NULL, row, clist_row);
|
|
}
|
|
|
|
void
|
|
gtk_clist_set_shift (GtkCList * clist,
|
|
gint row,
|
|
gint column,
|
|
gint vertical,
|
|
gint horizontal)
|
|
{
|
|
GtkCListRow *clist_row;
|
|
|
|
g_return_if_fail (clist != NULL);
|
|
|
|
if (row < 0 || row >= clist->rows)
|
|
return;
|
|
if (column < 0 || column >= clist->columns)
|
|
return;
|
|
|
|
clist_row = (g_list_nth (clist->row_list, row))->data;
|
|
|
|
clist_row->cell[column].vertical = vertical;
|
|
clist_row->cell[column].horizontal = horizontal;
|
|
|
|
if (!GTK_CLIST_FROZEN (clist) && gtk_clist_row_is_visible (clist, row))
|
|
draw_row (clist, NULL, row, clist_row);
|
|
}
|
|
|
|
gint
|
|
gtk_clist_append (GtkCList * clist,
|
|
gchar * text[])
|
|
{
|
|
gint i;
|
|
GtkCListRow *clist_row;
|
|
|
|
g_return_val_if_fail (clist != NULL, -1);
|
|
|
|
clist_row = row_new (clist);
|
|
clist->rows++;
|
|
|
|
/* set the text in the row's columns */
|
|
if (text)
|
|
for (i = 0; i < clist->columns; i++)
|
|
if (text[i])
|
|
cell_set_text (clist, clist_row, i, text[i]);
|
|
|
|
/* keeps track of the end of the list so the list
|
|
* doesn't have to be traversed every time a item is added */
|
|
if (!clist->row_list)
|
|
{
|
|
clist->row_list = g_list_append (clist->row_list, clist_row);
|
|
clist->row_list_end = clist->row_list;
|
|
|
|
/* check the selection mode to see if we should select
|
|
* the first row automaticly */
|
|
switch (clist->selection_mode)
|
|
{
|
|
case GTK_SELECTION_BROWSE:
|
|
gtk_clist_select_row (clist, 0, -1);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
clist->row_list_end = (g_list_append (clist->row_list_end, clist_row))->next;
|
|
|
|
/* redraw the list if it's not frozen */
|
|
if (!GTK_CLIST_FROZEN (clist))
|
|
{
|
|
adjust_scrollbars (clist);
|
|
|
|
if (gtk_clist_row_is_visible (clist, clist->rows - 1))
|
|
draw_rows (clist, NULL);
|
|
}
|
|
|
|
/* return index of the row */
|
|
return clist->rows - 1;
|
|
}
|
|
|
|
void
|
|
gtk_clist_insert (GtkCList * clist,
|
|
gint row,
|
|
gchar * text[])
|
|
{
|
|
gint i;
|
|
GtkCListRow *clist_row;
|
|
|
|
g_return_if_fail (clist != NULL);
|
|
g_return_if_fail (text != NULL);
|
|
|
|
/* return if out of bounds */
|
|
if (row < 0 || row > clist->rows)
|
|
return;
|
|
|
|
if (clist->rows == 0)
|
|
gtk_clist_append (clist, text);
|
|
else
|
|
{
|
|
/* create the row */
|
|
clist_row = row_new (clist);
|
|
|
|
/* set the text in the row's columns */
|
|
if (text)
|
|
for (i = 0; i < clist->columns; i++)
|
|
if (text[i])
|
|
cell_set_text (clist, clist_row, i, text[i]);
|
|
|
|
/* reset the row end pointer if we're inserting at the
|
|
* end of the list */
|
|
if (row == clist->rows)
|
|
clist->row_list_end = (g_list_append (clist->row_list_end, clist_row))->next;
|
|
else
|
|
clist->row_list = g_list_insert (clist->row_list, clist_row, row);
|
|
|
|
clist->rows++;
|
|
|
|
/* syncronize the selection list */
|
|
sync_selection (clist, row, SYNC_INSERT);
|
|
}
|
|
|
|
/* redraw the list if it isn't frozen */
|
|
if (!GTK_CLIST_FROZEN (clist))
|
|
{
|
|
adjust_scrollbars (clist);
|
|
|
|
if (gtk_clist_row_is_visible (clist, row))
|
|
draw_rows (clist, NULL);
|
|
}
|
|
}
|
|
|
|
void
|
|
gtk_clist_remove (GtkCList * clist,
|
|
gint row)
|
|
{
|
|
gint was_visible, was_selected;
|
|
GList *list;
|
|
GtkCListRow *clist_row;
|
|
|
|
g_return_if_fail (clist != NULL);
|
|
|
|
/* return if out of bounds */
|
|
if (row < 0 || row > (clist->rows - 1))
|
|
return;
|
|
|
|
was_visible = gtk_clist_row_is_visible (clist, row);
|
|
was_selected = 0;
|
|
|
|
/* get the row we're going to delete */
|
|
list = g_list_nth (clist->row_list, row);
|
|
clist_row = list->data;
|
|
|
|
/* if we're removing a selected row, we have to make sure
|
|
* it's properly unselected, and then sync up the clist->selected
|
|
* list to reflect the deincrimented indexies of rows after the
|
|
* removal */
|
|
if (clist_row->state == GTK_STATE_SELECTED)
|
|
{
|
|
was_selected = 1;
|
|
|
|
switch (clist->selection_mode)
|
|
{
|
|
case GTK_SELECTION_SINGLE:
|
|
case GTK_SELECTION_BROWSE:
|
|
case GTK_SELECTION_MULTIPLE:
|
|
gtk_clist_unselect_row (clist, row, -1);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* reset the row end pointer if we're removing at the
|
|
* end of the list */
|
|
if (row == clist->rows - 1)
|
|
clist->row_list_end = list->prev;
|
|
|
|
clist->row_list = g_list_remove (clist->row_list, clist_row);
|
|
clist->rows--;
|
|
sync_selection (clist, row, SYNC_REMOVE);
|
|
|
|
/* preform any selections required by the selection mode */
|
|
if (was_selected)
|
|
{
|
|
switch (clist->selection_mode)
|
|
{
|
|
case GTK_SELECTION_BROWSE:
|
|
if (row == clist->rows)
|
|
gtk_clist_select_row (clist, row - 1, -1);
|
|
else
|
|
gtk_clist_select_row (clist, row, -1);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* toast the row */
|
|
row_delete (clist, clist_row);
|
|
|
|
/* redraw the row if it isn't frozen */
|
|
if (!GTK_CLIST_FROZEN (clist))
|
|
{
|
|
adjust_scrollbars (clist);
|
|
|
|
if (was_visible)
|
|
draw_rows (clist, NULL);
|
|
}
|
|
}
|
|
|
|
static void
|
|
sync_selection (GtkCList * clist,
|
|
gint row,
|
|
gint mode)
|
|
{
|
|
GList *list;
|
|
|
|
list = clist->selection;
|
|
while (list)
|
|
{
|
|
if ((gint) list->data >= row)
|
|
switch (mode)
|
|
{
|
|
case SYNC_INSERT:
|
|
(gint) list->data = (gint) list->data + 1;
|
|
break;
|
|
|
|
case SYNC_REMOVE:
|
|
(gint) list->data = (gint) list->data - 1;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
list = list->next;
|
|
}
|
|
}
|
|
|
|
void
|
|
gtk_clist_clear (GtkCList * clist)
|
|
{
|
|
GList *list;
|
|
|
|
g_return_if_fail (clist != NULL);
|
|
|
|
/* remove all the rows */
|
|
for (list = clist->row_list; list; list = list->next)
|
|
{
|
|
GtkCListRow *clist_row;
|
|
|
|
clist_row = list->data;
|
|
row_delete (clist, clist_row);
|
|
}
|
|
g_list_free (clist->row_list);
|
|
|
|
/* free up the selection list */
|
|
g_list_free (clist->selection);
|
|
|
|
clist->row_list = NULL;
|
|
clist->row_list_end = NULL;
|
|
clist->selection = NULL;
|
|
clist->voffset = 0;
|
|
clist->rows = 0;
|
|
|
|
/* zero-out the scrollbars */
|
|
if (clist->vscrollbar)
|
|
{
|
|
GTK_RANGE (clist->vscrollbar)->adjustment->value = 0.0;
|
|
gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), "changed");
|
|
|
|
if (!GTK_CLIST_FROZEN (clist))
|
|
{
|
|
adjust_scrollbars (clist);
|
|
draw_rows (clist, NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
gtk_clist_set_row_data (GtkCList * clist,
|
|
gint row,
|
|
gpointer data)
|
|
{
|
|
gtk_clist_set_row_data_full (clist, row, data, NULL);
|
|
}
|
|
|
|
void
|
|
gtk_clist_set_row_data_full (GtkCList * clist,
|
|
gint row,
|
|
gpointer data,
|
|
GtkDestroyNotify destroy)
|
|
{
|
|
GtkCListRow *clist_row;
|
|
|
|
g_return_if_fail (clist != NULL);
|
|
|
|
if (row < 0 || row > (clist->rows - 1))
|
|
return;
|
|
|
|
clist_row = (g_list_nth (clist->row_list, row))->data;
|
|
clist_row->data = data;
|
|
clist_row->destroy = destroy;
|
|
|
|
/* re-send the selected signal if data is changed/added
|
|
* so the application can respond to the new data --
|
|
* this could be questionable behavior */
|
|
if (clist_row->state == GTK_STATE_SELECTED)
|
|
gtk_clist_select_row (clist, 0, 0);
|
|
}
|
|
|
|
gpointer
|
|
gtk_clist_get_row_data (GtkCList * clist,
|
|
gint row)
|
|
{
|
|
GtkCListRow *clist_row;
|
|
|
|
g_return_val_if_fail (clist != NULL, NULL);
|
|
|
|
if (row < 0 || row > (clist->rows - 1))
|
|
return NULL;
|
|
|
|
clist_row = (g_list_nth (clist->row_list, row))->data;
|
|
return clist_row->data;
|
|
}
|
|
|
|
gint
|
|
gtk_clist_find_row_from_data (GtkCList * clist,
|
|
gpointer data)
|
|
{
|
|
GList *list;
|
|
gint n;
|
|
|
|
g_return_val_if_fail (clist != NULL, -1);
|
|
g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
|
|
|
|
if (clist->rows < 1)
|
|
return -1; /* is this an optimization or just worthless? */
|
|
|
|
n = 0;
|
|
list = clist->row_list;
|
|
while (list)
|
|
{
|
|
GtkCListRow *clist_row;
|
|
|
|
clist_row = list->data;
|
|
if (clist_row->data == data)
|
|
break;
|
|
n++;
|
|
list = list->next;
|
|
}
|
|
|
|
if (list)
|
|
return n;
|
|
|
|
return -1;
|
|
}
|
|
|
|
void
|
|
gtk_clist_select_row (GtkCList * clist,
|
|
gint row,
|
|
gint column)
|
|
{
|
|
g_return_if_fail (clist != NULL);
|
|
|
|
if (row < 0 || row >= clist->rows)
|
|
return;
|
|
|
|
if (column < -1 || column >= clist->columns)
|
|
return;
|
|
|
|
select_row (clist, row, column, NULL);
|
|
}
|
|
|
|
void
|
|
gtk_clist_unselect_row (GtkCList * clist,
|
|
gint row,
|
|
gint column)
|
|
{
|
|
g_return_if_fail (clist != NULL);
|
|
|
|
if (row < 0 || row >= clist->rows)
|
|
return;
|
|
|
|
if (column < -1 || column >= clist->columns)
|
|
return;
|
|
|
|
unselect_row (clist, row, column, NULL);
|
|
}
|
|
|
|
gint
|
|
gtk_clist_row_is_visible (GtkCList * clist,
|
|
gint row)
|
|
{
|
|
g_return_val_if_fail (clist != NULL, 0);
|
|
|
|
if (row < 0 || row >= clist->rows)
|
|
return 0;
|
|
|
|
if (clist->row_height == 0)
|
|
return 0;
|
|
|
|
if (row < ROW_FROM_YPIXEL (clist, 0))
|
|
return 0;
|
|
|
|
if (row > ROW_FROM_YPIXEL (clist, clist->clist_window_height))
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
GtkAdjustment *
|
|
gtk_clist_get_vadjustment (GtkCList * clist)
|
|
{
|
|
g_return_val_if_fail (clist != NULL, NULL);
|
|
g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
|
|
|
|
return gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar));
|
|
}
|
|
|
|
GtkAdjustment *
|
|
gtk_clist_get_hadjustment (GtkCList * clist)
|
|
{
|
|
g_return_val_if_fail (clist != NULL, NULL);
|
|
g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
|
|
|
|
return gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar));
|
|
}
|
|
|
|
void
|
|
gtk_clist_set_policy (GtkCList * clist,
|
|
GtkPolicyType vscrollbar_policy,
|
|
GtkPolicyType hscrollbar_policy)
|
|
{
|
|
g_return_if_fail (clist != NULL);
|
|
g_return_if_fail (GTK_IS_CLIST (clist));
|
|
|
|
if (clist->vscrollbar_policy != vscrollbar_policy)
|
|
{
|
|
clist->vscrollbar_policy = vscrollbar_policy;
|
|
|
|
if (GTK_WIDGET (clist)->parent)
|
|
gtk_widget_queue_resize (GTK_WIDGET (clist));
|
|
}
|
|
|
|
if (clist->hscrollbar_policy != hscrollbar_policy)
|
|
{
|
|
clist->hscrollbar_policy = hscrollbar_policy;
|
|
|
|
if (GTK_WIDGET (clist)->parent)
|
|
gtk_widget_queue_resize (GTK_WIDGET (clist));
|
|
}
|
|
}
|
|
|
|
/*
|
|
* GTKOBJECT
|
|
* gtk_clist_destroy
|
|
* gtk_clist_finalize
|
|
*/
|
|
static void
|
|
gtk_clist_destroy (GtkObject * object)
|
|
{
|
|
gint i;
|
|
GtkCList *clist;
|
|
|
|
g_return_if_fail (object != NULL);
|
|
g_return_if_fail (GTK_IS_CLIST (object));
|
|
|
|
clist = GTK_CLIST (object);
|
|
|
|
/* freeze the list */
|
|
GTK_CLIST_SET_FLAGS (clist, CLIST_FROZEN);
|
|
|
|
/* get rid of all the rows */
|
|
gtk_clist_clear (clist);
|
|
|
|
/* Since we don't have a _remove method, unparent the children
|
|
* instead of destroying them so the focus will be unset properly.
|
|
* (For other containers, the _remove method takes care of the
|
|
* unparent) The destroy will happen when the refcount drops
|
|
* to zero.
|
|
*/
|
|
|
|
/* destroy the scrollbars */
|
|
if (clist->vscrollbar)
|
|
{
|
|
gtk_widget_unparent (clist->vscrollbar);
|
|
clist->vscrollbar = NULL;
|
|
}
|
|
if (clist->hscrollbar)
|
|
{
|
|
gtk_widget_unparent (clist->hscrollbar);
|
|
clist->hscrollbar = NULL;
|
|
}
|
|
|
|
/* destroy the column buttons */
|
|
for (i = 0; i < clist->columns; i++)
|
|
if (clist->column[i].button)
|
|
{
|
|
gtk_widget_unparent (clist->column[i].button);
|
|
clist->column[i].button = NULL;
|
|
}
|
|
|
|
if (GTK_OBJECT_CLASS (parent_class)->destroy)
|
|
(*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
|
|
}
|
|
|
|
static void
|
|
gtk_clist_finalize (GtkObject * object)
|
|
{
|
|
GtkCList *clist;
|
|
|
|
g_return_if_fail (object != NULL);
|
|
g_return_if_fail (GTK_IS_CLIST (object));
|
|
|
|
clist = GTK_CLIST (object);
|
|
|
|
columns_delete (clist);
|
|
|
|
g_mem_chunk_destroy (clist->cell_mem_chunk);
|
|
g_mem_chunk_destroy (clist->row_mem_chunk);
|
|
|
|
if (GTK_OBJECT_CLASS (parent_class)->finalize)
|
|
(*GTK_OBJECT_CLASS (parent_class)->finalize) (object);
|
|
}
|
|
|
|
/*
|
|
* GTKWIDGET
|
|
* gtk_clist_realize
|
|
* gtk_clist_unrealize
|
|
* gtk_clist_map
|
|
* gtk_clist_unmap
|
|
* gtk_clist_draw
|
|
* gtk_clist_expose
|
|
* gtk_clist_button_press
|
|
* gtk_clist_button_release
|
|
* gtk_clist_button_motion
|
|
* gtk_clist_size_request
|
|
* gtk_clist_size_allocate
|
|
*/
|
|
static void
|
|
gtk_clist_realize (GtkWidget * widget)
|
|
{
|
|
gint i;
|
|
GtkCList *clist;
|
|
GdkWindowAttr attributes;
|
|
gint attributes_mask;
|
|
GdkGCValues values;
|
|
|
|
g_return_if_fail (widget != NULL);
|
|
g_return_if_fail (GTK_IS_CLIST (widget));
|
|
|
|
clist = GTK_CLIST (widget);
|
|
|
|
GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
|
|
|
|
attributes.window_type = GDK_WINDOW_CHILD;
|
|
attributes.x = widget->allocation.x;
|
|
attributes.y = widget->allocation.y;
|
|
attributes.width = widget->allocation.width;
|
|
attributes.height = widget->allocation.height;
|
|
attributes.wclass = GDK_INPUT_OUTPUT;
|
|
attributes.visual = gtk_widget_get_visual (widget);
|
|
attributes.colormap = gtk_widget_get_colormap (widget);
|
|
attributes.event_mask = gtk_widget_get_events (widget);
|
|
attributes.event_mask |= (GDK_EXPOSURE_MASK |
|
|
GDK_BUTTON_PRESS_MASK |
|
|
GDK_BUTTON_RELEASE_MASK |
|
|
GDK_KEY_PRESS_MASK);
|
|
attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
|
|
|
|
|
|
/* main window */
|
|
widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
|
|
gdk_window_set_user_data (widget->window, clist);
|
|
|
|
widget->style = gtk_style_attach (widget->style, widget->window);
|
|
|
|
gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
|
|
|
|
/* column-title window */
|
|
clist->title_window = gdk_window_new (widget->window, &attributes, attributes_mask);
|
|
gdk_window_set_user_data (clist->title_window, clist);
|
|
|
|
gtk_style_set_background (widget->style, clist->title_window, GTK_STATE_SELECTED);
|
|
gdk_window_show (clist->title_window);
|
|
|
|
/* set things up so column buttons are drawn in title window */
|
|
for (i = 0; i < clist->columns; i++)
|
|
if (clist->column[i].button)
|
|
gtk_widget_set_parent_window (clist->column[i].button, clist->title_window);
|
|
|
|
/* clist-window */
|
|
clist->clist_window = gdk_window_new (widget->window, &attributes, attributes_mask);
|
|
gdk_window_set_user_data (clist->clist_window, clist);
|
|
|
|
gdk_window_set_background (clist->clist_window, &widget->style->bg[GTK_STATE_PRELIGHT]);
|
|
gdk_window_show (clist->clist_window);
|
|
gdk_window_get_size (clist->clist_window, &clist->clist_window_width,
|
|
&clist->clist_window_height);
|
|
|
|
/* create resize windows */
|
|
attributes.wclass = GDK_INPUT_ONLY;
|
|
attributes.event_mask = (GDK_BUTTON_PRESS_MASK |
|
|
GDK_BUTTON_RELEASE_MASK |
|
|
GDK_POINTER_MOTION_MASK |
|
|
GDK_POINTER_MOTION_HINT_MASK);
|
|
attributes.cursor = clist->cursor_drag = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW);
|
|
attributes_mask = GDK_WA_CURSOR;
|
|
|
|
for (i = 0; i < clist->columns; i++)
|
|
{
|
|
clist->column[i].window = gdk_window_new (clist->title_window, &attributes, attributes_mask);
|
|
gdk_window_set_user_data (clist->column[i].window, clist);
|
|
gdk_window_show (clist->column[i].window);
|
|
}
|
|
|
|
/* GCs */
|
|
clist->fg_gc = gdk_gc_new (widget->window);
|
|
clist->bg_gc = gdk_gc_new (widget->window);
|
|
|
|
/* We'll use this gc to do scrolling as well */
|
|
gdk_gc_set_exposures (clist->fg_gc, TRUE);
|
|
|
|
values.foreground = widget->style->white;
|
|
values.function = GDK_XOR;
|
|
values.subwindow_mode = GDK_INCLUDE_INFERIORS;
|
|
clist->xor_gc = gdk_gc_new_with_values (widget->window,
|
|
&values,
|
|
GDK_GC_FOREGROUND |
|
|
GDK_GC_FUNCTION |
|
|
GDK_GC_SUBWINDOW);
|
|
|
|
add_style_data (clist);
|
|
}
|
|
|
|
static void
|
|
gtk_clist_unrealize (GtkWidget * widget)
|
|
{
|
|
gint i;
|
|
GtkCList *clist;
|
|
|
|
g_return_if_fail (widget != NULL);
|
|
g_return_if_fail (GTK_IS_CLIST (widget));
|
|
|
|
clist = GTK_CLIST (widget);
|
|
|
|
GTK_CLIST_SET_FLAGS (clist, CLIST_FROZEN);
|
|
|
|
gdk_cursor_destroy (clist->cursor_drag);
|
|
gdk_gc_destroy (clist->xor_gc);
|
|
gdk_gc_destroy (clist->fg_gc);
|
|
gdk_gc_destroy (clist->bg_gc);
|
|
|
|
for (i = 0; i < clist->columns; i++)
|
|
if (clist->column[i].window)
|
|
{
|
|
gdk_window_set_user_data (clist->column[i].window, NULL);
|
|
gdk_window_destroy (clist->column[i].window);
|
|
clist->column[i].window = NULL;
|
|
}
|
|
|
|
gdk_window_set_user_data (clist->clist_window, NULL);
|
|
gdk_window_destroy (clist->clist_window);
|
|
clist->clist_window = NULL;
|
|
|
|
gdk_window_set_user_data (clist->title_window, NULL);
|
|
gdk_window_destroy (clist->title_window);
|
|
clist->title_window = NULL;
|
|
|
|
clist->cursor_drag = NULL;
|
|
clist->xor_gc = NULL;
|
|
clist->fg_gc = NULL;
|
|
clist->bg_gc = NULL;
|
|
|
|
if (GTK_WIDGET_CLASS (parent_class)->unrealize)
|
|
(* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
|
|
}
|
|
|
|
static void
|
|
gtk_clist_map (GtkWidget * widget)
|
|
{
|
|
gint i;
|
|
GtkCList *clist;
|
|
|
|
g_return_if_fail (widget != NULL);
|
|
g_return_if_fail (GTK_IS_CLIST (widget));
|
|
|
|
clist = GTK_CLIST (widget);
|
|
|
|
if (!GTK_WIDGET_MAPPED (widget))
|
|
{
|
|
GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
|
|
|
|
gdk_window_show (widget->window);
|
|
gdk_window_show (clist->title_window);
|
|
gdk_window_show (clist->clist_window);
|
|
|
|
/* map column buttons */
|
|
for (i = 0; i < clist->columns; i++)
|
|
if (clist->column[i].button &&
|
|
GTK_WIDGET_VISIBLE (clist->column[i].button) &&
|
|
!GTK_WIDGET_MAPPED (clist->column[i].button))
|
|
gtk_widget_map (clist->column[i].button);
|
|
|
|
/* map resize windows AFTER column buttons (above) */
|
|
for (i = 0; i < clist->columns; i++)
|
|
if (clist->column[i].window && clist->column[i].button)
|
|
gdk_window_show (clist->column[i].window);
|
|
|
|
/* map vscrollbars */
|
|
if (GTK_WIDGET_VISIBLE (clist->vscrollbar) &&
|
|
!GTK_WIDGET_MAPPED (clist->vscrollbar))
|
|
gtk_widget_map (clist->vscrollbar);
|
|
|
|
if (GTK_WIDGET_VISIBLE (clist->hscrollbar) &&
|
|
!GTK_WIDGET_MAPPED (clist->hscrollbar))
|
|
gtk_widget_map (clist->hscrollbar);
|
|
|
|
/* unfreeze the list */
|
|
GTK_CLIST_UNSET_FLAGS (clist, CLIST_FROZEN);
|
|
}
|
|
}
|
|
|
|
static void
|
|
gtk_clist_unmap (GtkWidget * widget)
|
|
{
|
|
gint i;
|
|
GtkCList *clist;
|
|
|
|
g_return_if_fail (widget != NULL);
|
|
g_return_if_fail (GTK_IS_CLIST (widget));
|
|
|
|
clist = GTK_CLIST (widget);
|
|
|
|
if (GTK_WIDGET_MAPPED (widget))
|
|
{
|
|
GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
|
|
|
|
for (i = 0; i < clist->columns; i++)
|
|
if (clist->column[i].window)
|
|
gdk_window_hide (clist->column[i].window);
|
|
|
|
gdk_window_hide (clist->clist_window);
|
|
gdk_window_hide (clist->title_window);
|
|
gdk_window_hide (widget->window);
|
|
|
|
/* unmap scrollbars */
|
|
if (GTK_WIDGET_MAPPED (clist->vscrollbar))
|
|
gtk_widget_unmap (clist->vscrollbar);
|
|
|
|
if (GTK_WIDGET_MAPPED (clist->hscrollbar))
|
|
gtk_widget_unmap (clist->hscrollbar);
|
|
|
|
/* unmap column buttons */
|
|
for (i = 0; i < clist->columns; i++)
|
|
if (clist->column[i].button &&
|
|
GTK_WIDGET_MAPPED (clist->column[i].button))
|
|
gtk_widget_unmap (clist->column[i].button);
|
|
|
|
/* freeze the list */
|
|
GTK_CLIST_SET_FLAGS (clist, CLIST_FROZEN);
|
|
}
|
|
}
|
|
|
|
static void
|
|
gtk_clist_draw (GtkWidget * widget,
|
|
GdkRectangle * area)
|
|
{
|
|
GtkCList *clist;
|
|
|
|
g_return_if_fail (widget != NULL);
|
|
g_return_if_fail (GTK_IS_CLIST (widget));
|
|
g_return_if_fail (area != NULL);
|
|
|
|
if (GTK_WIDGET_DRAWABLE (widget))
|
|
{
|
|
clist = GTK_CLIST (widget);
|
|
|
|
gdk_window_clear_area (widget->window,
|
|
area->x, area->y,
|
|
area->width, area->height);
|
|
|
|
/* draw list shadow/border */
|
|
gtk_draw_shadow (widget->style, widget->window,
|
|
GTK_STATE_NORMAL, clist->shadow_type,
|
|
0, 0,
|
|
clist->clist_window_width + (2 * widget->style->klass->xthickness),
|
|
clist->clist_window_height + (2 * widget->style->klass->ythickness) +
|
|
clist->column_title_area.height);
|
|
|
|
gdk_window_clear_area (clist->clist_window,
|
|
0, 0, -1, -1);
|
|
|
|
draw_rows (clist, NULL);
|
|
}
|
|
}
|
|
|
|
static gint
|
|
gtk_clist_expose (GtkWidget * widget,
|
|
GdkEventExpose * event)
|
|
{
|
|
GtkCList *clist;
|
|
|
|
g_return_val_if_fail (widget != NULL, FALSE);
|
|
g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
|
|
g_return_val_if_fail (event != NULL, FALSE);
|
|
|
|
if (GTK_WIDGET_DRAWABLE (widget))
|
|
{
|
|
clist = GTK_CLIST (widget);
|
|
|
|
/* draw border */
|
|
if (event->window == widget->window)
|
|
gtk_draw_shadow (widget->style, widget->window,
|
|
GTK_STATE_NORMAL, clist->shadow_type,
|
|
0, 0,
|
|
clist->clist_window_width + (2 * widget->style->klass->xthickness),
|
|
clist->clist_window_height + (2 * widget->style->klass->ythickness) +
|
|
clist->column_title_area.height);
|
|
|
|
/* exposure events on the list */
|
|
if (event->window == clist->clist_window)
|
|
draw_rows (clist, &event->area);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gint
|
|
gtk_clist_button_press (GtkWidget * widget,
|
|
GdkEventButton * event)
|
|
{
|
|
gint i;
|
|
GtkCList *clist;
|
|
gint x, y, row, column;
|
|
|
|
g_return_val_if_fail (widget != NULL, FALSE);
|
|
g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
|
|
g_return_val_if_fail (event != NULL, FALSE);
|
|
|
|
clist = GTK_CLIST (widget);
|
|
|
|
/* selections on the list */
|
|
if (event->window == clist->clist_window)
|
|
{
|
|
x = event->x;
|
|
y = event->y;
|
|
|
|
if (get_selection_info (clist, x, y, &row, &column))
|
|
toggle_row (clist, row, column, event);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/* press on resize windows */
|
|
for (i = 0; i < clist->columns; i++)
|
|
if (clist->column[i].window && event->window == clist->column[i].window)
|
|
{
|
|
GTK_CLIST_SET_FLAGS (clist, CLIST_IN_DRAG);
|
|
gtk_widget_get_pointer (widget, &clist->x_drag, NULL);
|
|
|
|
gdk_pointer_grab (clist->column[i].window, FALSE,
|
|
GDK_POINTER_MOTION_HINT_MASK |
|
|
GDK_BUTTON1_MOTION_MASK |
|
|
GDK_BUTTON_RELEASE_MASK,
|
|
NULL, NULL, event->time);
|
|
|
|
draw_xor_line (clist);
|
|
return FALSE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gint
|
|
gtk_clist_button_release (GtkWidget * widget,
|
|
GdkEventButton * event)
|
|
{
|
|
gint i, x, width, visible;
|
|
GtkCList *clist;
|
|
|
|
g_return_val_if_fail (widget != NULL, FALSE);
|
|
g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
|
|
g_return_val_if_fail (event != NULL, FALSE);
|
|
|
|
clist = GTK_CLIST (widget);
|
|
|
|
/* release on resize windows */
|
|
if (GTK_CLIST_IN_DRAG (clist))
|
|
for (i = 0; i < clist->columns; i++)
|
|
if (clist->column[i].window && event->window == clist->column[i].window)
|
|
{
|
|
GTK_CLIST_UNSET_FLAGS (clist, CLIST_IN_DRAG);
|
|
gtk_widget_get_pointer (widget, &x, NULL);
|
|
width = new_column_width (clist, i, &x, &visible);
|
|
gdk_pointer_ungrab (event->time);
|
|
|
|
if (visible)
|
|
draw_xor_line (clist);
|
|
|
|
resize_column (clist, i, width);
|
|
return FALSE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gint
|
|
gtk_clist_motion (GtkWidget * widget,
|
|
GdkEventMotion * event)
|
|
{
|
|
gint i, x, visible;
|
|
GtkCList *clist;
|
|
|
|
g_return_val_if_fail (widget != NULL, FALSE);
|
|
g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
|
|
|
|
clist = GTK_CLIST (widget);
|
|
|
|
if (GTK_CLIST_IN_DRAG (clist))
|
|
for (i = 0; i < clist->columns; i++)
|
|
if (clist->column[i].window && event->window == clist->column[i].window)
|
|
{
|
|
if (event->is_hint || event->window != widget->window)
|
|
gtk_widget_get_pointer (widget, &x, NULL);
|
|
else
|
|
x = event->x;
|
|
|
|
new_column_width (clist, i, &x, &visible);
|
|
/* Welcome to my hack! I'm going to use a value of x_drage = -99999 to
|
|
* indicate the the xor line is already no visible */
|
|
if (!visible && clist->x_drag != -99999)
|
|
{
|
|
draw_xor_line (clist);
|
|
clist->x_drag = -99999;
|
|
}
|
|
|
|
if (x != clist->x_drag && visible)
|
|
{
|
|
if (clist->x_drag != -99999)
|
|
draw_xor_line (clist);
|
|
|
|
clist->x_drag = x;
|
|
draw_xor_line (clist);
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
gtk_clist_size_request (GtkWidget * widget,
|
|
GtkRequisition * requisition)
|
|
{
|
|
gint i;
|
|
GtkCList *clist;
|
|
|
|
g_return_if_fail (widget != NULL);
|
|
g_return_if_fail (GTK_IS_CLIST (widget));
|
|
g_return_if_fail (requisition != NULL);
|
|
|
|
clist = GTK_CLIST (widget);
|
|
|
|
requisition->width = 0;
|
|
requisition->height = 0;
|
|
|
|
/* compute the size of the column title (title) area */
|
|
clist->column_title_area.height = 0;
|
|
if (GTK_CLIST_SHOW_TITLES (clist))
|
|
for (i = 0; i < clist->columns; i++)
|
|
if (clist->column[i].button)
|
|
{
|
|
gtk_widget_size_request (clist->column[i].button, &clist->column[i].button->requisition);
|
|
clist->column_title_area.height = MAX (clist->column_title_area.height,
|
|
clist->column[i].button->requisition.height);
|
|
}
|
|
requisition->height += clist->column_title_area.height;
|
|
|
|
/* add the vscrollbar space */
|
|
if ((clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC) ||
|
|
GTK_WIDGET_VISIBLE (clist->vscrollbar))
|
|
{
|
|
gtk_widget_size_request (clist->vscrollbar, &clist->vscrollbar->requisition);
|
|
|
|
requisition->width += clist->vscrollbar->requisition.width + SCROLLBAR_SPACING (clist);
|
|
requisition->height = MAX (requisition->height,
|
|
clist->vscrollbar->requisition.height);
|
|
}
|
|
|
|
/* add the hscrollbar space */
|
|
if ((clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC) ||
|
|
GTK_WIDGET_VISIBLE (clist->hscrollbar))
|
|
{
|
|
gtk_widget_size_request (clist->hscrollbar, &clist->hscrollbar->requisition);
|
|
|
|
requisition->height += clist->hscrollbar->requisition.height + SCROLLBAR_SPACING (clist);
|
|
requisition->width = MAX (clist->hscrollbar->requisition.width,
|
|
requisition->width -
|
|
clist->vscrollbar->requisition.width);
|
|
|
|
}
|
|
|
|
requisition->width += widget->style->klass->xthickness * 2 +
|
|
GTK_CONTAINER (widget)->border_width * 2;
|
|
requisition->height += widget->style->klass->ythickness * 2 +
|
|
GTK_CONTAINER (widget)->border_width * 2;
|
|
}
|
|
|
|
static void
|
|
gtk_clist_size_allocate (GtkWidget * widget,
|
|
GtkAllocation * allocation)
|
|
{
|
|
GtkCList *clist;
|
|
GtkAllocation clist_allocation;
|
|
GtkAllocation child_allocation;
|
|
gint i, vscrollbar_vis, hscrollbar_vis;
|
|
|
|
g_return_if_fail (widget != NULL);
|
|
g_return_if_fail (GTK_IS_CLIST (widget));
|
|
g_return_if_fail (allocation != NULL);
|
|
|
|
clist = GTK_CLIST (widget);
|
|
widget->allocation = *allocation;
|
|
|
|
if (GTK_WIDGET_REALIZED (widget))
|
|
{
|
|
gdk_window_move_resize (widget->window,
|
|
allocation->x + GTK_CONTAINER (widget)->border_width,
|
|
allocation->y + GTK_CONTAINER (widget)->border_width,
|
|
allocation->width - GTK_CONTAINER (widget)->border_width * 2,
|
|
allocation->height - GTK_CONTAINER (widget)->border_width * 2);
|
|
|
|
/* use internal allocation structure for all the math
|
|
* because it's easier than always subtracting the container
|
|
* border width */
|
|
clist->internal_allocation.x = 0;
|
|
clist->internal_allocation.y = 0;
|
|
clist->internal_allocation.width = allocation->width -
|
|
GTK_CONTAINER (widget)->border_width * 2;
|
|
clist->internal_allocation.height = allocation->height -
|
|
GTK_CONTAINER (widget)->border_width * 2;
|
|
|
|
/* allocate clist window assuming no scrollbars */
|
|
clist_allocation.x = clist->internal_allocation.x + widget->style->klass->xthickness;
|
|
clist_allocation.y = clist->internal_allocation.y + widget->style->klass->ythickness +
|
|
clist->column_title_area.height;
|
|
clist_allocation.width = clist->internal_allocation.width -
|
|
(2 * widget->style->klass->xthickness);
|
|
clist_allocation.height = clist->internal_allocation.height -
|
|
(2 * widget->style->klass->xthickness) -
|
|
clist->column_title_area.height;
|
|
|
|
/*
|
|
* here's where we decide to show/not show the scrollbars
|
|
*/
|
|
vscrollbar_vis = 0;
|
|
hscrollbar_vis = 0;
|
|
|
|
for (i = 0; i <= 1; i++)
|
|
{
|
|
if (LIST_HEIGHT (clist) <= clist_allocation.height &&
|
|
clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
|
|
{
|
|
vscrollbar_vis = 0;
|
|
}
|
|
else
|
|
{
|
|
if (!vscrollbar_vis)
|
|
{
|
|
vscrollbar_vis = 1;
|
|
clist_allocation.width -= clist->vscrollbar->requisition.width +
|
|
SCROLLBAR_SPACING (clist);
|
|
}
|
|
}
|
|
|
|
if (LIST_WIDTH (clist) <= clist_allocation.width &&
|
|
clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
|
|
{
|
|
hscrollbar_vis = 0;
|
|
}
|
|
else
|
|
{
|
|
if (!hscrollbar_vis)
|
|
{
|
|
hscrollbar_vis = 1;
|
|
clist_allocation.height -= clist->hscrollbar->requisition.height +
|
|
SCROLLBAR_SPACING (clist);
|
|
}
|
|
}
|
|
}
|
|
|
|
clist->clist_window_width = clist_allocation.width;
|
|
clist->clist_window_height = clist_allocation.height;
|
|
|
|
gdk_window_move_resize (clist->clist_window,
|
|
clist_allocation.x,
|
|
clist_allocation.y,
|
|
clist_allocation.width,
|
|
clist_allocation.height);
|
|
|
|
/* position the window which holds the column title buttons */
|
|
clist->column_title_area.x = widget->style->klass->xthickness;
|
|
clist->column_title_area.y = widget->style->klass->ythickness;
|
|
clist->column_title_area.width = clist_allocation.width;
|
|
|
|
gdk_window_move_resize (clist->title_window,
|
|
clist->column_title_area.x,
|
|
clist->column_title_area.y,
|
|
clist->column_title_area.width,
|
|
clist->column_title_area.height);
|
|
|
|
/* column button allocation */
|
|
size_allocate_columns (clist);
|
|
size_allocate_title_buttons (clist);
|
|
adjust_scrollbars (clist);
|
|
|
|
/* allocate the vscrollbar */
|
|
if (vscrollbar_vis)
|
|
{
|
|
if (!GTK_WIDGET_VISIBLE (clist->vscrollbar))
|
|
gtk_widget_show (clist->vscrollbar);
|
|
|
|
child_allocation.x = clist->internal_allocation.x +
|
|
clist->internal_allocation.width -
|
|
clist->vscrollbar->requisition.width;
|
|
child_allocation.y = clist->internal_allocation.y;
|
|
child_allocation.width = clist->vscrollbar->requisition.width;
|
|
child_allocation.height = clist->internal_allocation.height -
|
|
(hscrollbar_vis ? (clist->hscrollbar->requisition.height + SCROLLBAR_SPACING (clist)) : 0);
|
|
|
|
gtk_widget_size_allocate (clist->vscrollbar, &child_allocation);
|
|
}
|
|
else
|
|
{
|
|
if (GTK_WIDGET_VISIBLE (clist->vscrollbar))
|
|
gtk_widget_hide (clist->vscrollbar);
|
|
}
|
|
|
|
if (hscrollbar_vis)
|
|
{
|
|
if (!GTK_WIDGET_VISIBLE (clist->hscrollbar))
|
|
gtk_widget_show (clist->hscrollbar);
|
|
|
|
child_allocation.x = clist->internal_allocation.x;
|
|
child_allocation.y = clist->internal_allocation.y +
|
|
clist->internal_allocation.height -
|
|
clist->hscrollbar->requisition.height;
|
|
child_allocation.width = clist->internal_allocation.width -
|
|
(vscrollbar_vis ? (clist->vscrollbar->requisition.width + SCROLLBAR_SPACING (clist)) : 0);
|
|
child_allocation.height = clist->hscrollbar->requisition.height;
|
|
|
|
gtk_widget_size_allocate (clist->hscrollbar, &child_allocation);
|
|
}
|
|
else
|
|
{
|
|
if (GTK_WIDGET_VISIBLE (clist->hscrollbar))
|
|
gtk_widget_hide (clist->hscrollbar);
|
|
}
|
|
}
|
|
|
|
/* set the vscrollbar adjustments */
|
|
adjust_scrollbars (clist);
|
|
}
|
|
|
|
/*
|
|
* GTKCONTAINER
|
|
* gtk_clist_foreach
|
|
*/
|
|
static void
|
|
gtk_clist_foreach (GtkContainer * container,
|
|
GtkCallback callback,
|
|
gpointer callback_data)
|
|
{
|
|
gint i;
|
|
GtkCList *clist;
|
|
|
|
g_return_if_fail (container != NULL);
|
|
g_return_if_fail (GTK_IS_CLIST (container));
|
|
g_return_if_fail (callback != NULL);
|
|
|
|
clist = GTK_CLIST (container);
|
|
|
|
/* callback for the column buttons */
|
|
for (i = 0; i < clist->columns; i++)
|
|
if (clist->column[i].button)
|
|
(*callback) (clist->column[i].button, callback_data);
|
|
|
|
/* callbacks for the scrollbars */
|
|
if (clist->vscrollbar)
|
|
(*callback) (clist->vscrollbar, callback_data);
|
|
if (clist->hscrollbar)
|
|
(*callback) (clist->hscrollbar, callback_data);
|
|
}
|
|
|
|
/*
|
|
* DRAWING
|
|
* draw_row
|
|
* draw_rows
|
|
*/
|
|
static void
|
|
draw_row (GtkCList * clist,
|
|
GdkRectangle * area,
|
|
gint row,
|
|
GtkCListRow * clist_row)
|
|
{
|
|
GtkWidget *widget;
|
|
GdkGC *fg_gc, *bg_gc;
|
|
GdkRectangle row_rectangle, cell_rectangle, clip_rectangle, intersect_rectangle,
|
|
*rect;
|
|
gint i, offset = 0, width, height, pixmap_width = 0;
|
|
gint xsrc, ysrc, xdest, ydest;
|
|
|
|
g_return_if_fail (clist != NULL);
|
|
|
|
/* bail now if we arn't drawable yet */
|
|
if (!GTK_WIDGET_DRAWABLE (clist))
|
|
return;
|
|
|
|
if (row < 0 || row >= clist->rows)
|
|
return;
|
|
|
|
widget = GTK_WIDGET (clist);
|
|
|
|
/* if the function is passed the pointer to the row instead of null,
|
|
* it avoids this expensive lookup */
|
|
if (!clist_row)
|
|
clist_row = (g_list_nth (clist->row_list, row))->data;
|
|
|
|
/* rectangle of the entire row */
|
|
row_rectangle.x = 0;
|
|
row_rectangle.y = ROW_TOP_YPIXEL (clist, row);
|
|
row_rectangle.width = clist->clist_window_width;
|
|
row_rectangle.height = clist->row_height;
|
|
|
|
/* rectangle of the cell spacing above the row */
|
|
cell_rectangle.x = 0;
|
|
cell_rectangle.y = row_rectangle.y - CELL_SPACING;
|
|
cell_rectangle.width = row_rectangle.width;
|
|
cell_rectangle.height = CELL_SPACING;
|
|
|
|
/* rectangle used to clip drawing operations, it's y and height
|
|
* positions only need to be set once, so we set them once here.
|
|
* the x and width are set withing the drawing loop below once per
|
|
* column */
|
|
clip_rectangle.y = row_rectangle.y;
|
|
clip_rectangle.height = row_rectangle.height;
|
|
|
|
/* select GC for background rectangle */
|
|
if (clist_row->state == GTK_STATE_SELECTED)
|
|
{
|
|
fg_gc = widget->style->fg_gc[GTK_STATE_SELECTED];
|
|
bg_gc = widget->style->bg_gc[GTK_STATE_SELECTED];
|
|
}
|
|
else
|
|
{
|
|
if (clist_row->fg_set)
|
|
{
|
|
gdk_gc_set_foreground (clist->fg_gc, &clist_row->foreground);
|
|
fg_gc = clist->fg_gc;
|
|
}
|
|
else
|
|
fg_gc = widget->style->fg_gc[GTK_STATE_NORMAL];
|
|
|
|
if (clist_row->bg_set)
|
|
{
|
|
gdk_gc_set_foreground (clist->bg_gc, &clist_row->background);
|
|
bg_gc = clist->bg_gc;
|
|
}
|
|
else
|
|
bg_gc = widget->style->bg_gc[GTK_STATE_PRELIGHT];
|
|
}
|
|
|
|
/* draw the cell borders and background */
|
|
if (area)
|
|
{
|
|
if (gdk_rectangle_intersect (area, &cell_rectangle, &intersect_rectangle))
|
|
gdk_draw_rectangle (clist->clist_window,
|
|
widget->style->white_gc,
|
|
TRUE,
|
|
intersect_rectangle.x,
|
|
intersect_rectangle.y,
|
|
intersect_rectangle.width,
|
|
intersect_rectangle.height);
|
|
|
|
/* the last row has to clear it's bottom cell spacing too */
|
|
if (clist_row == clist->row_list_end->data)
|
|
{
|
|
cell_rectangle.y += clist->row_height + CELL_SPACING;
|
|
|
|
if (gdk_rectangle_intersect (area, &cell_rectangle, &intersect_rectangle))
|
|
gdk_draw_rectangle (clist->clist_window,
|
|
widget->style->white_gc,
|
|
TRUE,
|
|
intersect_rectangle.x,
|
|
intersect_rectangle.y,
|
|
intersect_rectangle.width,
|
|
intersect_rectangle.height);
|
|
}
|
|
|
|
if (!gdk_rectangle_intersect (area, &row_rectangle, &intersect_rectangle))
|
|
return;
|
|
|
|
if (clist_row->state == GTK_STATE_SELECTED || clist_row->fg_set)
|
|
gdk_draw_rectangle (clist->clist_window,
|
|
bg_gc,
|
|
TRUE,
|
|
intersect_rectangle.x,
|
|
intersect_rectangle.y,
|
|
intersect_rectangle.width,
|
|
intersect_rectangle.height);
|
|
else
|
|
gdk_window_clear_area (clist->clist_window,
|
|
intersect_rectangle.x,
|
|
intersect_rectangle.y,
|
|
intersect_rectangle.width,
|
|
intersect_rectangle.height);
|
|
}
|
|
else
|
|
{
|
|
gdk_draw_rectangle (clist->clist_window,
|
|
widget->style->white_gc,
|
|
TRUE,
|
|
cell_rectangle.x,
|
|
cell_rectangle.y,
|
|
cell_rectangle.width,
|
|
cell_rectangle.height);
|
|
|
|
/* the last row has to clear it's bottom cell spacing too */
|
|
if (clist_row == clist->row_list_end->data)
|
|
{
|
|
cell_rectangle.y += clist->row_height + CELL_SPACING;
|
|
|
|
gdk_draw_rectangle (clist->clist_window,
|
|
widget->style->white_gc,
|
|
TRUE,
|
|
cell_rectangle.x,
|
|
cell_rectangle.y,
|
|
cell_rectangle.width,
|
|
cell_rectangle.height);
|
|
}
|
|
|
|
if (clist_row->state == GTK_STATE_SELECTED || clist_row->fg_set)
|
|
gdk_draw_rectangle (clist->clist_window,
|
|
bg_gc,
|
|
TRUE,
|
|
row_rectangle.x,
|
|
row_rectangle.y,
|
|
row_rectangle.width,
|
|
row_rectangle.height);
|
|
else
|
|
gdk_window_clear_area (clist->clist_window,
|
|
row_rectangle.x,
|
|
row_rectangle.y,
|
|
row_rectangle.width,
|
|
row_rectangle.height);
|
|
}
|
|
|
|
/* iterate and draw all the columns (row cells) and draw their contents */
|
|
for (i = 0; i < clist->columns; i++)
|
|
{
|
|
clip_rectangle.x = clist->column[i].area.x + clist->hoffset;
|
|
clip_rectangle.width = clist->column[i].area.width;
|
|
|
|
/* calculate clipping region clipping region */
|
|
if (!area)
|
|
{
|
|
rect = &clip_rectangle;
|
|
}
|
|
else
|
|
{
|
|
if (!gdk_rectangle_intersect (area, &clip_rectangle, &intersect_rectangle))
|
|
continue;
|
|
rect = &intersect_rectangle;
|
|
}
|
|
|
|
/* calculate real width for column justification */
|
|
switch (clist_row->cell[i].type)
|
|
{
|
|
case GTK_CELL_EMPTY:
|
|
continue;
|
|
break;
|
|
|
|
case GTK_CELL_TEXT:
|
|
width = gdk_string_width (GTK_WIDGET (clist)->style->font,
|
|
GTK_CELL_TEXT (clist_row->cell[i])->text);
|
|
break;
|
|
|
|
case GTK_CELL_PIXMAP:
|
|
gdk_window_get_size (GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap, &width, &height);
|
|
pixmap_width = width;
|
|
break;
|
|
|
|
case GTK_CELL_PIXTEXT:
|
|
gdk_window_get_size (GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap, &width, &height);
|
|
pixmap_width = width;
|
|
width += GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing;
|
|
width = gdk_string_width (GTK_WIDGET (clist)->style->font,
|
|
GTK_CELL_PIXTEXT (clist_row->cell[i])->text);
|
|
break;
|
|
|
|
case GTK_CELL_WIDGET:
|
|
/* unimplimented */
|
|
continue;
|
|
break;
|
|
|
|
default:
|
|
continue;
|
|
break;
|
|
}
|
|
|
|
switch (clist->column[i].justification)
|
|
{
|
|
case GTK_JUSTIFY_LEFT:
|
|
offset = clip_rectangle.x;
|
|
break;
|
|
|
|
case GTK_JUSTIFY_RIGHT:
|
|
offset = (clip_rectangle.x + clip_rectangle.width) - width;
|
|
break;
|
|
|
|
case GTK_JUSTIFY_CENTER:
|
|
offset = (clip_rectangle.x + (clip_rectangle.width / 2)) - (width / 2);
|
|
break;
|
|
|
|
case GTK_JUSTIFY_FILL:
|
|
offset = (clip_rectangle.x + (clip_rectangle.width / 2)) - (width / 2);
|
|
break;
|
|
|
|
default:
|
|
offset = 0;
|
|
break;
|
|
};
|
|
|
|
/* Draw Text or Pixmap */
|
|
switch (clist_row->cell[i].type)
|
|
{
|
|
case GTK_CELL_EMPTY:
|
|
continue;
|
|
break;
|
|
|
|
case GTK_CELL_TEXT:
|
|
gdk_gc_set_clip_rectangle (fg_gc, rect);
|
|
|
|
gdk_draw_string (clist->clist_window,
|
|
widget->style->font,
|
|
fg_gc,
|
|
offset + clist_row->cell[i].horizontal,
|
|
row_rectangle.y + clist->row_center_offset +
|
|
clist_row->cell[i].vertical,
|
|
GTK_CELL_TEXT (clist_row->cell[i])->text);
|
|
|
|
gdk_gc_set_clip_rectangle (fg_gc, NULL);
|
|
break;
|
|
|
|
case GTK_CELL_PIXMAP:
|
|
xsrc = 0;
|
|
ysrc = 0;
|
|
xdest = offset + clist_row->cell[i].horizontal;
|
|
ydest = (clip_rectangle.y + (clip_rectangle.height / 2)) - height / 2 +
|
|
clist_row->cell[i].vertical;
|
|
|
|
if (GTK_CELL_PIXMAP (clist_row->cell[i])->mask)
|
|
{
|
|
gdk_gc_set_clip_mask (fg_gc, GTK_CELL_PIXMAP (clist_row->cell[i])->mask);
|
|
gdk_gc_set_clip_origin (fg_gc, xdest, ydest);
|
|
}
|
|
gdk_draw_pixmap (clist->clist_window,
|
|
fg_gc,
|
|
GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap,
|
|
xsrc, ysrc,
|
|
xdest,
|
|
ydest,
|
|
pixmap_width, height);
|
|
|
|
if (GTK_CELL_PIXMAP (clist_row->cell[i])->mask)
|
|
{
|
|
gdk_gc_set_clip_origin (fg_gc, 0, 0);
|
|
gdk_gc_set_clip_mask (fg_gc, NULL);
|
|
}
|
|
break;
|
|
|
|
case GTK_CELL_PIXTEXT:
|
|
/* draw the pixmap */
|
|
xsrc = 0;
|
|
ysrc = 0;
|
|
xdest = offset + clist_row->cell[i].horizontal;
|
|
ydest = (clip_rectangle.y + (clip_rectangle.height / 2)) - height / 2 +
|
|
clist_row->cell[i].vertical;
|
|
|
|
if (GTK_CELL_PIXTEXT (clist_row->cell[i])->mask)
|
|
{
|
|
gdk_gc_set_clip_mask (fg_gc, GTK_CELL_PIXTEXT (clist_row->cell[i])->mask);
|
|
gdk_gc_set_clip_origin (fg_gc, xdest, ydest);
|
|
}
|
|
|
|
gdk_draw_pixmap (clist->clist_window,
|
|
fg_gc,
|
|
GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap,
|
|
xsrc, ysrc,
|
|
xdest,
|
|
ydest,
|
|
pixmap_width, height);
|
|
|
|
gdk_gc_set_clip_origin (fg_gc, 0, 0);
|
|
|
|
offset += pixmap_width + GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing;
|
|
|
|
/* draw the string */
|
|
gdk_gc_set_clip_rectangle (fg_gc, rect);
|
|
|
|
gdk_draw_string (clist->clist_window,
|
|
widget->style->font,
|
|
fg_gc,
|
|
offset + clist_row->cell[i].horizontal,
|
|
row_rectangle.y + clist->row_center_offset +
|
|
clist_row->cell[i].vertical,
|
|
GTK_CELL_PIXTEXT (clist_row->cell[i])->text);
|
|
|
|
gdk_gc_set_clip_rectangle (fg_gc, NULL);
|
|
|
|
break;
|
|
|
|
case GTK_CELL_WIDGET:
|
|
/* unimplimented */
|
|
continue;
|
|
break;
|
|
|
|
default:
|
|
continue;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
draw_rows (GtkCList * clist,
|
|
GdkRectangle * area)
|
|
{
|
|
GList *list;
|
|
GtkCListRow *clist_row;
|
|
int i, first_row, last_row;
|
|
|
|
g_return_if_fail (clist != NULL);
|
|
g_return_if_fail (GTK_IS_CLIST (clist));
|
|
|
|
if (clist->row_height == 0 ||
|
|
!GTK_WIDGET_DRAWABLE (clist))
|
|
return;
|
|
|
|
if (area)
|
|
{
|
|
first_row = ROW_FROM_YPIXEL (clist, area->y);
|
|
last_row = ROW_FROM_YPIXEL (clist, area->y + area->height);
|
|
}
|
|
else
|
|
{
|
|
first_row = ROW_FROM_YPIXEL (clist, 0);
|
|
last_row = ROW_FROM_YPIXEL (clist, clist->clist_window_height);
|
|
}
|
|
|
|
/* this is a small special case which exposes the bottom cell line
|
|
* on the last row -- it might go away if I change the wall the cell spacings
|
|
* are drawn */
|
|
if (clist->rows == first_row)
|
|
first_row--;
|
|
|
|
list = g_list_nth (clist->row_list, first_row);
|
|
i = first_row;
|
|
while (list)
|
|
{
|
|
clist_row = list->data;
|
|
list = list->next;
|
|
|
|
if (i > last_row)
|
|
return;
|
|
|
|
draw_row (clist, area, i, clist_row);
|
|
i++;
|
|
}
|
|
|
|
if (!area)
|
|
gdk_window_clear_area (clist->clist_window, 0, ROW_TOP_YPIXEL (clist, i), -1, -1);
|
|
}
|
|
|
|
/*
|
|
* SIZE ALLOCATION
|
|
* size_allocate_title_buttons
|
|
* size_allocate_columns
|
|
*/
|
|
static void
|
|
size_allocate_title_buttons (GtkCList * clist)
|
|
{
|
|
gint i, last_button = 0;
|
|
GtkAllocation button_allocation;
|
|
|
|
if (!GTK_WIDGET_REALIZED (clist))
|
|
return;
|
|
|
|
button_allocation.x = clist->hoffset;
|
|
button_allocation.y = 0;
|
|
button_allocation.width = 0;
|
|
button_allocation.height = clist->column_title_area.height;
|
|
|
|
for (i = 0; i < clist->columns; i++)
|
|
{
|
|
button_allocation.width += clist->column[i].area.width;
|
|
|
|
if (i == clist->columns - 1)
|
|
button_allocation.width += 2 * (CELL_SPACING + COLUMN_INSET);
|
|
else
|
|
button_allocation.width += CELL_SPACING + (2 * COLUMN_INSET);
|
|
|
|
if (i == (clist->columns - 1) || clist->column[i + 1].button)
|
|
{
|
|
gtk_widget_size_allocate (clist->column[last_button].button, &button_allocation);
|
|
button_allocation.x += button_allocation.width;
|
|
button_allocation.width = 0;
|
|
|
|
gdk_window_show (clist->column[last_button].window);
|
|
gdk_window_move_resize (clist->column[last_button].window,
|
|
button_allocation.x - (DRAG_WIDTH / 2),
|
|
0, DRAG_WIDTH, clist->column_title_area.height);
|
|
|
|
last_button = i + 1;
|
|
}
|
|
else
|
|
{
|
|
gdk_window_hide (clist->column[i].window);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
size_allocate_columns (GtkCList * clist)
|
|
{
|
|
gint i, xoffset = 0;
|
|
|
|
if (!GTK_WIDGET_REALIZED (clist))
|
|
return;
|
|
|
|
for (i = 0; i < clist->columns; i++)
|
|
{
|
|
clist->column[i].area.x = xoffset + CELL_SPACING + COLUMN_INSET;
|
|
|
|
if (i == clist->columns - 1)
|
|
{
|
|
gint width;
|
|
|
|
if (clist->column[i].width_set)
|
|
width = clist->column[i].width;
|
|
else
|
|
width = gdk_string_width (GTK_WIDGET (clist)->style->font, clist->column[i].title);
|
|
clist->column[i].area.width = MAX (width,
|
|
clist->clist_window_width -
|
|
xoffset - (2 * (CELL_SPACING + COLUMN_INSET)));
|
|
|
|
}
|
|
else
|
|
{
|
|
clist->column[i].area.width = clist->column[i].width;
|
|
}
|
|
|
|
xoffset += clist->column[i].area.width + CELL_SPACING + (2 * COLUMN_INSET);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* SELECTION
|
|
* select_row
|
|
* real_select_row
|
|
* real_unselect_row
|
|
* get_selection_info
|
|
*/
|
|
static void
|
|
toggle_row (GtkCList * clist,
|
|
gint row,
|
|
gint column,
|
|
GdkEventButton * event)
|
|
{
|
|
gint i;
|
|
GList *list;
|
|
GtkCListRow *clist_row, *selected_row;
|
|
|
|
i = 0;
|
|
list = clist->row_list;
|
|
selected_row = NULL;
|
|
|
|
switch (clist->selection_mode)
|
|
{
|
|
case GTK_SELECTION_SINGLE:
|
|
while (list)
|
|
{
|
|
clist_row = list->data;
|
|
list = list->next;
|
|
|
|
if (row == i)
|
|
selected_row = clist_row;
|
|
else if (clist_row->state == GTK_STATE_SELECTED)
|
|
gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
|
|
i, column, event);
|
|
|
|
i++;
|
|
}
|
|
|
|
if (selected_row && selected_row->state == GTK_STATE_SELECTED)
|
|
gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
|
|
row, column, event);
|
|
else
|
|
gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
|
|
row, column, event);
|
|
break;
|
|
|
|
|
|
case GTK_SELECTION_BROWSE:
|
|
while (list)
|
|
{
|
|
clist_row = list->data;
|
|
list = list->next;
|
|
|
|
if (i != row && clist_row->state == GTK_STATE_SELECTED)
|
|
gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
|
|
i, column, event);
|
|
i++;
|
|
}
|
|
|
|
gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
|
|
row, column, event);
|
|
break;
|
|
|
|
|
|
case GTK_SELECTION_MULTIPLE:
|
|
clist_row = (g_list_nth (clist->row_list, row))->data;
|
|
|
|
if (clist_row->state == GTK_STATE_SELECTED)
|
|
gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
|
|
row, column, event);
|
|
else
|
|
gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
|
|
row, column, event);
|
|
break;
|
|
|
|
|
|
case GTK_SELECTION_EXTENDED:
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
select_row (GtkCList * clist,
|
|
gint row,
|
|
gint column,
|
|
GdkEventButton * event)
|
|
{
|
|
gint i;
|
|
GList *list;
|
|
GtkCListRow *clist_row;
|
|
|
|
switch (clist->selection_mode)
|
|
{
|
|
case GTK_SELECTION_SINGLE:
|
|
case GTK_SELECTION_BROWSE:
|
|
i = 0;
|
|
list = clist->row_list;
|
|
while (list)
|
|
{
|
|
clist_row = list->data;
|
|
list = list->next;
|
|
|
|
if (row != i && clist_row->state == GTK_STATE_SELECTED)
|
|
gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
|
|
i, column, event);
|
|
|
|
i++;
|
|
}
|
|
|
|
gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
|
|
row, column, event);
|
|
break;
|
|
|
|
case GTK_SELECTION_MULTIPLE:
|
|
gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
|
|
row, column, event);
|
|
|
|
break;
|
|
|
|
case GTK_SELECTION_EXTENDED:
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
unselect_row (GtkCList * clist,
|
|
gint row,
|
|
gint column,
|
|
GdkEventButton * event)
|
|
{
|
|
switch (clist->selection_mode)
|
|
{
|
|
case GTK_SELECTION_SINGLE:
|
|
case GTK_SELECTION_BROWSE:
|
|
case GTK_SELECTION_MULTIPLE:
|
|
gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW],
|
|
row, column, event);
|
|
break;
|
|
|
|
case GTK_SELECTION_EXTENDED:
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
real_select_row (GtkCList * clist,
|
|
gint row,
|
|
gint column,
|
|
GdkEventButton * event)
|
|
{
|
|
GtkCListRow *clist_row;
|
|
|
|
g_return_if_fail (clist != NULL);
|
|
|
|
if (row < 0 || row > (clist->rows - 1))
|
|
return;
|
|
|
|
clist_row = (g_list_nth (clist->row_list, row))->data;
|
|
|
|
if (clist_row->state == GTK_STATE_NORMAL)
|
|
{
|
|
clist_row->state = GTK_STATE_SELECTED;
|
|
clist->selection = g_list_append (clist->selection, (gpointer) row);
|
|
|
|
if (!GTK_CLIST_FROZEN (clist) && gtk_clist_row_is_visible (clist, row))
|
|
draw_row (clist, NULL, row, clist_row);
|
|
}
|
|
}
|
|
|
|
static void
|
|
real_unselect_row (GtkCList * clist,
|
|
gint row,
|
|
gint column,
|
|
GdkEventButton * event)
|
|
{
|
|
GtkCListRow *clist_row;
|
|
|
|
g_return_if_fail (clist != NULL);
|
|
|
|
if (row < 0 || row > (clist->rows - 1))
|
|
return;
|
|
|
|
clist_row = (g_list_nth (clist->row_list, row))->data;
|
|
|
|
if (clist_row->state == GTK_STATE_SELECTED)
|
|
{
|
|
clist_row->state = GTK_STATE_NORMAL;
|
|
clist->selection = g_list_remove (clist->selection, (gpointer) row);
|
|
|
|
if (!GTK_CLIST_FROZEN (clist) && gtk_clist_row_is_visible (clist, row))
|
|
draw_row (clist, NULL, row, clist_row);
|
|
}
|
|
}
|
|
|
|
static gint
|
|
get_selection_info (GtkCList * clist,
|
|
gint x,
|
|
gint y,
|
|
gint * row,
|
|
gint * column)
|
|
{
|
|
gint trow, tcol;
|
|
|
|
g_return_val_if_fail (clist != NULL, 0);
|
|
|
|
/* bounds checking, return false if the user clicked
|
|
* on a blank area */
|
|
trow = ROW_FROM_YPIXEL (clist, y);
|
|
if (trow >= clist->rows)
|
|
return 0;
|
|
|
|
if (row)
|
|
*row = trow;
|
|
|
|
tcol = COLUMN_FROM_XPIXEL (clist, x);
|
|
if (tcol >= clist->columns)
|
|
return 0;
|
|
|
|
if (column)
|
|
*column = tcol;
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* RESIZE COLUMNS
|
|
* draw_xor_line
|
|
* new_column_width
|
|
* resize_column
|
|
*/
|
|
static void
|
|
draw_xor_line (GtkCList * clist)
|
|
{
|
|
GtkWidget *widget;
|
|
|
|
g_return_if_fail (clist != NULL);
|
|
|
|
widget = GTK_WIDGET (clist);
|
|
|
|
gdk_draw_line (widget->window, clist->xor_gc,
|
|
clist->x_drag,
|
|
widget->style->klass->ythickness,
|
|
clist->x_drag,
|
|
clist->column_title_area.height + clist->clist_window_height + 1);
|
|
}
|
|
|
|
/* this function returns the new width of the column being resized given
|
|
* the column and x position of the cursor; the x cursor position is passed
|
|
* in as a pointer and automagicly corrected if it's beyond min/max limits */
|
|
static gint
|
|
new_column_width (GtkCList * clist,
|
|
gint column,
|
|
gint * x,
|
|
gint * visible)
|
|
{
|
|
gint cx, rx, width;
|
|
|
|
cx = *x;
|
|
|
|
/* first translate the x position from widget->window
|
|
* to clist->clist_window */
|
|
cx -= GTK_WIDGET (clist)->style->klass->xthickness;
|
|
|
|
/* rx is x from the list beginning */
|
|
rx = cx - clist->hoffset;
|
|
|
|
/* you can't shrink a column to less than its minimum width */
|
|
if (cx < (COLUMN_LEFT_XPIXEL (clist, column) + CELL_SPACING + COLUMN_INSET + COLUMN_MIN_WIDTH))
|
|
{
|
|
*x = cx = COLUMN_LEFT_XPIXEL (clist, column) + CELL_SPACING + COLUMN_INSET + COLUMN_MIN_WIDTH +
|
|
GTK_WIDGET (clist)->style->klass->xthickness;
|
|
cx -= GTK_WIDGET (clist)->style->klass->xthickness;
|
|
rx = cx - clist->hoffset;
|
|
}
|
|
|
|
if (cx > clist->clist_window_width)
|
|
*visible = 0;
|
|
else
|
|
*visible = 1;
|
|
|
|
/* calculate new column width making sure it doesn't end up
|
|
* less than the minimum width */
|
|
width = (rx - COLUMN_LEFT (clist, column)) - COLUMN_INSET -
|
|
((clist->columns == (column - 1)) ? CELL_SPACING : 0);
|
|
if (width < COLUMN_MIN_WIDTH)
|
|
width = COLUMN_MIN_WIDTH;
|
|
|
|
return width;
|
|
}
|
|
|
|
/* this will do more later */
|
|
static void
|
|
resize_column (GtkCList * clist,
|
|
gint column,
|
|
gint width)
|
|
{
|
|
gtk_clist_set_column_width (clist, column, width);
|
|
}
|
|
|
|
/* BUTTONS */
|
|
static void
|
|
column_button_create (GtkCList * clist,
|
|
gint column)
|
|
{
|
|
GtkWidget *button;
|
|
|
|
button = clist->column[column].button = gtk_button_new ();
|
|
gtk_widget_set_parent (button, GTK_WIDGET (clist));
|
|
if (GTK_WIDGET_REALIZED (clist) && clist->title_window)
|
|
gtk_widget_set_parent_window (clist->column[column].button, clist->title_window);
|
|
|
|
gtk_signal_connect (GTK_OBJECT (button),
|
|
"clicked",
|
|
(GtkSignalFunc) column_button_clicked,
|
|
(gpointer) clist);
|
|
|
|
gtk_widget_show (button);
|
|
}
|
|
|
|
static void
|
|
column_button_clicked (GtkWidget * widget,
|
|
gpointer data)
|
|
{
|
|
gint i;
|
|
GtkCList *clist;
|
|
|
|
g_return_if_fail (widget != NULL);
|
|
g_return_if_fail (GTK_IS_CLIST (data));
|
|
|
|
clist = GTK_CLIST (data);
|
|
|
|
/* find the column who's button was pressed */
|
|
for (i = 0; i < clist->columns; i++)
|
|
if (clist->column[i].button == widget)
|
|
break;
|
|
|
|
gtk_signal_emit (GTK_OBJECT (clist), clist_signals[CLICK_COLUMN], i);
|
|
}
|
|
|
|
/*
|
|
* SCROLLBARS
|
|
*
|
|
* functions:
|
|
* create_scrollbars
|
|
* adjust_scrollbars
|
|
* vadjustment_changed
|
|
* hadjustment_changed
|
|
* vadjustment_value_changed
|
|
* hadjustment_value_changed
|
|
*/
|
|
static void
|
|
create_scrollbars (GtkCList * clist)
|
|
{
|
|
GtkAdjustment *adjustment;
|
|
|
|
clist->vscrollbar = gtk_vscrollbar_new (NULL);
|
|
adjustment = gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar));
|
|
|
|
gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
|
|
(GtkSignalFunc) vadjustment_changed,
|
|
(gpointer) clist);
|
|
|
|
gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
|
|
(GtkSignalFunc) vadjustment_value_changed,
|
|
(gpointer) clist);
|
|
|
|
gtk_widget_set_parent (clist->vscrollbar, GTK_WIDGET (clist));
|
|
gtk_widget_show (clist->vscrollbar);
|
|
|
|
clist->hscrollbar = gtk_hscrollbar_new (NULL);
|
|
adjustment = gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar));
|
|
|
|
gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
|
|
(GtkSignalFunc) hadjustment_changed,
|
|
(gpointer) clist);
|
|
|
|
gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
|
|
(GtkSignalFunc) hadjustment_value_changed,
|
|
(gpointer) clist);
|
|
|
|
gtk_widget_set_parent (clist->hscrollbar, GTK_WIDGET (clist));
|
|
gtk_widget_show (clist->hscrollbar);
|
|
}
|
|
|
|
static void
|
|
adjust_scrollbars (GtkCList * clist)
|
|
{
|
|
GTK_RANGE (clist->vscrollbar)->adjustment->page_size = clist->clist_window_height;
|
|
GTK_RANGE (clist->vscrollbar)->adjustment->page_increment = clist->clist_window_height / 2;
|
|
GTK_RANGE (clist->vscrollbar)->adjustment->step_increment = 10;
|
|
GTK_RANGE (clist->vscrollbar)->adjustment->lower = 0;
|
|
GTK_RANGE (clist->vscrollbar)->adjustment->upper = LIST_HEIGHT (clist);
|
|
|
|
if (clist->clist_window_height - clist->voffset > LIST_HEIGHT (clist))
|
|
{
|
|
GTK_RANGE (clist->vscrollbar)->adjustment->value = LIST_HEIGHT (clist) -
|
|
clist->clist_window_height;
|
|
gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment),
|
|
"value_changed");
|
|
}
|
|
|
|
GTK_RANGE (clist->hscrollbar)->adjustment->page_size = clist->clist_window_width;
|
|
GTK_RANGE (clist->hscrollbar)->adjustment->page_increment = clist->clist_window_width / 2;
|
|
GTK_RANGE (clist->hscrollbar)->adjustment->step_increment = 10;
|
|
GTK_RANGE (clist->hscrollbar)->adjustment->lower = 0;
|
|
GTK_RANGE (clist->hscrollbar)->adjustment->upper = LIST_WIDTH (clist);
|
|
|
|
if (clist->clist_window_width - clist->hoffset > LIST_WIDTH (clist))
|
|
{
|
|
GTK_RANGE (clist->hscrollbar)->adjustment->value = LIST_WIDTH (clist) -
|
|
clist->clist_window_width;
|
|
gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->hscrollbar)->adjustment),
|
|
"value_changed");
|
|
}
|
|
|
|
if (LIST_HEIGHT (clist) <= clist->clist_window_height &&
|
|
clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
|
|
{
|
|
if (GTK_WIDGET_VISIBLE (clist->vscrollbar))
|
|
{
|
|
gtk_widget_hide (clist->vscrollbar);
|
|
gtk_widget_queue_resize (GTK_WIDGET (clist));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!GTK_WIDGET_VISIBLE (clist->vscrollbar))
|
|
{
|
|
gtk_widget_show (clist->vscrollbar);
|
|
gtk_widget_queue_resize (GTK_WIDGET (clist));
|
|
}
|
|
}
|
|
|
|
if (LIST_WIDTH (clist) <= clist->clist_window_width &&
|
|
clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
|
|
{
|
|
if (GTK_WIDGET_VISIBLE (clist->hscrollbar))
|
|
{
|
|
gtk_widget_hide (clist->hscrollbar);
|
|
gtk_widget_queue_resize (GTK_WIDGET (clist));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!GTK_WIDGET_VISIBLE (clist->hscrollbar))
|
|
{
|
|
gtk_widget_show (clist->hscrollbar);
|
|
gtk_widget_queue_resize (GTK_WIDGET (clist));
|
|
}
|
|
}
|
|
|
|
gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), "changed");
|
|
gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->hscrollbar)->adjustment), "changed");
|
|
}
|
|
|
|
static void
|
|
vadjustment_changed (GtkAdjustment * adjustment,
|
|
gpointer data)
|
|
{
|
|
GtkCList *clist;
|
|
|
|
g_return_if_fail (adjustment != NULL);
|
|
g_return_if_fail (data != NULL);
|
|
|
|
clist = GTK_CLIST (data);
|
|
}
|
|
|
|
static void
|
|
hadjustment_changed (GtkAdjustment * adjustment,
|
|
gpointer data)
|
|
{
|
|
GtkCList *clist;
|
|
|
|
g_return_if_fail (adjustment != NULL);
|
|
g_return_if_fail (data != NULL);
|
|
|
|
clist = GTK_CLIST (data);
|
|
}
|
|
|
|
static void
|
|
check_exposures (GtkCList *clist)
|
|
{
|
|
GdkEvent *event;
|
|
|
|
if (!GTK_WIDGET_REALIZED (clist))
|
|
return;
|
|
|
|
/* Make sure graphics expose events are processed before scrolling
|
|
* again */
|
|
while ((event = gdk_event_get_graphics_expose (clist->clist_window)) != NULL)
|
|
{
|
|
gtk_widget_event (GTK_WIDGET (clist), event);
|
|
if (event->expose.count == 0)
|
|
{
|
|
gdk_event_free (event);
|
|
break;
|
|
}
|
|
gdk_event_free (event);
|
|
}
|
|
}
|
|
|
|
static void
|
|
vadjustment_value_changed (GtkAdjustment * adjustment,
|
|
gpointer data)
|
|
{
|
|
GtkCList *clist;
|
|
GdkRectangle area;
|
|
gint diff, value;
|
|
|
|
g_return_if_fail (adjustment != NULL);
|
|
g_return_if_fail (data != NULL);
|
|
g_return_if_fail (GTK_IS_CLIST (data));
|
|
|
|
clist = GTK_CLIST (data);
|
|
|
|
if (!GTK_WIDGET_DRAWABLE (clist))
|
|
return;
|
|
|
|
value = adjustment->value;
|
|
|
|
if (adjustment == gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar)))
|
|
{
|
|
if (value > -clist->voffset)
|
|
{
|
|
/* scroll down */
|
|
diff = value + clist->voffset;
|
|
|
|
/* we have to re-draw the whole screen here... */
|
|
if (diff >= clist->clist_window_height)
|
|
{
|
|
clist->voffset = -value;
|
|
draw_rows (clist, NULL);
|
|
return;
|
|
}
|
|
|
|
if ((diff != 0) && (diff != clist->clist_window_height))
|
|
gdk_window_copy_area (clist->clist_window,
|
|
clist->fg_gc,
|
|
0, 0,
|
|
clist->clist_window,
|
|
0,
|
|
diff,
|
|
clist->clist_window_width,
|
|
clist->clist_window_height - diff);
|
|
|
|
area.x = 0;
|
|
area.y = clist->clist_window_height - diff;
|
|
area.width = clist->clist_window_width;
|
|
area.height = diff;
|
|
}
|
|
else
|
|
{
|
|
/* scroll up */
|
|
diff = -clist->voffset - value;
|
|
|
|
/* we have to re-draw the whole screen here... */
|
|
if (diff >= clist->clist_window_height)
|
|
{
|
|
clist->voffset = -value;
|
|
draw_rows (clist, NULL);
|
|
return;
|
|
}
|
|
|
|
if ((diff != 0) && (diff != clist->clist_window_height))
|
|
gdk_window_copy_area (clist->clist_window,
|
|
clist->fg_gc,
|
|
0, diff,
|
|
clist->clist_window,
|
|
0,
|
|
0,
|
|
clist->clist_window_width,
|
|
clist->clist_window_height - diff);
|
|
|
|
area.x = 0;
|
|
area.y = 0;
|
|
area.width = clist->clist_window_width;
|
|
area.height = diff;
|
|
|
|
}
|
|
|
|
clist->voffset = -value;
|
|
if ((diff != 0) && (diff != clist->clist_window_height))
|
|
check_exposures (clist);
|
|
}
|
|
|
|
draw_rows (clist, &area);
|
|
}
|
|
|
|
static void
|
|
hadjustment_value_changed (GtkAdjustment * adjustment,
|
|
gpointer data)
|
|
{
|
|
GtkCList *clist;
|
|
GdkRectangle area;
|
|
gint i, diff, value;
|
|
|
|
g_return_if_fail (adjustment != NULL);
|
|
g_return_if_fail (data != NULL);
|
|
g_return_if_fail (GTK_IS_CLIST (data));
|
|
|
|
clist = GTK_CLIST (data);
|
|
|
|
if (!GTK_WIDGET_DRAWABLE (clist))
|
|
return;
|
|
|
|
value = adjustment->value;
|
|
|
|
if (adjustment == gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar)))
|
|
{
|
|
/* move the column buttons and resize windows */
|
|
for (i = 0; i < clist->columns; i++)
|
|
{
|
|
if (clist->column[i].button)
|
|
{
|
|
clist->column[i].button->allocation.x -= value + clist->hoffset;
|
|
|
|
if (clist->column[i].button->window)
|
|
{
|
|
gdk_window_move (clist->column[i].button->window,
|
|
clist->column[i].button->allocation.x,
|
|
clist->column[i].button->allocation.y);
|
|
|
|
if (clist->column[i].window)
|
|
gdk_window_move (clist->column[i].window,
|
|
clist->column[i].button->allocation.x +
|
|
clist->column[i].button->allocation.width -
|
|
(DRAG_WIDTH / 2), 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (value > -clist->hoffset)
|
|
{
|
|
/* scroll right */
|
|
diff = value + clist->hoffset;
|
|
|
|
/* we have to re-draw the whole screen here... */
|
|
if (diff >= clist->clist_window_width)
|
|
{
|
|
clist->hoffset = -value;
|
|
draw_rows (clist, NULL);
|
|
return;
|
|
}
|
|
|
|
if ((diff != 0) && (diff != clist->clist_window_width))
|
|
gdk_window_copy_area (clist->clist_window,
|
|
clist->fg_gc,
|
|
0, 0,
|
|
clist->clist_window,
|
|
diff,
|
|
0,
|
|
clist->clist_window_width - diff,
|
|
clist->clist_window_height);
|
|
|
|
area.x = clist->clist_window_width - diff;
|
|
area.y = 0;
|
|
area.width = diff;
|
|
area.height = clist->clist_window_height;
|
|
}
|
|
else
|
|
{
|
|
/* scroll left */
|
|
diff = -clist->hoffset - value;
|
|
|
|
/* we have to re-draw the whole screen here... */
|
|
if (diff >= clist->clist_window_width)
|
|
{
|
|
clist->hoffset = -value;
|
|
draw_rows (clist, NULL);
|
|
return;
|
|
}
|
|
|
|
if ((diff != 0) && (diff != clist->clist_window_width))
|
|
gdk_window_copy_area (clist->clist_window,
|
|
clist->fg_gc,
|
|
diff, 0,
|
|
clist->clist_window,
|
|
0,
|
|
0,
|
|
clist->clist_window_width - diff,
|
|
clist->clist_window_height);
|
|
|
|
area.x = 0;
|
|
area.y = 0;
|
|
area.width = diff;
|
|
area.height = clist->clist_window_height;
|
|
}
|
|
|
|
clist->hoffset = -value;
|
|
if ((diff != 0) && (diff != clist->clist_window_width))
|
|
check_exposures (clist);
|
|
}
|
|
|
|
draw_rows (clist, &area);
|
|
}
|
|
|
|
/*
|
|
* Memory Allocation/Distruction Routines for GtkCList stuctures
|
|
*
|
|
* functions:
|
|
* columns_new
|
|
* column_title_new
|
|
* columns_delete
|
|
* row_new
|
|
* row_delete
|
|
* cell_empty
|
|
* cell_set_text
|
|
* cell_set_pixmap
|
|
*/
|
|
static GtkCListColumn *
|
|
columns_new (GtkCList * clist)
|
|
{
|
|
gint i;
|
|
GtkCListColumn *column;
|
|
|
|
column = g_new (GtkCListColumn, clist->columns);
|
|
|
|
for (i = 0; i < clist->columns; i++)
|
|
{
|
|
column[i].area.x = 0;
|
|
column[i].area.y = 0;
|
|
column[i].area.width = 0;
|
|
column[i].area.height = 0;
|
|
column[i].title = NULL;
|
|
column[i].button = NULL;
|
|
column[i].window = NULL;
|
|
column[i].width = 0;
|
|
column[i].width_set = FALSE;
|
|
column[i].justification = GTK_JUSTIFY_LEFT;
|
|
}
|
|
|
|
return column;
|
|
}
|
|
|
|
static void
|
|
column_title_new (GtkCList * clist,
|
|
gint column,
|
|
gchar * title)
|
|
{
|
|
if (clist->column[column].title)
|
|
g_free (clist->column[column].title);
|
|
|
|
clist->column[column].title = g_strdup (title);
|
|
}
|
|
|
|
static void
|
|
columns_delete (GtkCList * clist)
|
|
{
|
|
gint i;
|
|
|
|
for (i = 0; i < clist->columns; i++)
|
|
if (clist->column[i].title)
|
|
g_free (clist->column[i].title);
|
|
|
|
g_free (clist->column);
|
|
}
|
|
|
|
static GtkCListRow *
|
|
row_new (GtkCList * clist)
|
|
{
|
|
int i;
|
|
GtkCListRow *clist_row;
|
|
|
|
clist_row = g_chunk_new (GtkCListRow, clist->row_mem_chunk);
|
|
clist_row->cell = g_chunk_new (GtkCell, clist->cell_mem_chunk);
|
|
|
|
for (i = 0; i < clist->columns; i++)
|
|
{
|
|
clist_row->cell[i].type = GTK_CELL_EMPTY;
|
|
clist_row->cell[i].vertical = 0;
|
|
clist_row->cell[i].horizontal = 0;
|
|
}
|
|
|
|
clist_row->fg_set = FALSE;
|
|
clist_row->bg_set = FALSE;
|
|
clist_row->state = GTK_STATE_NORMAL;
|
|
clist_row->data = NULL;
|
|
clist_row->destroy = NULL;
|
|
|
|
return clist_row;
|
|
}
|
|
|
|
static void
|
|
row_delete (GtkCList * clist,
|
|
GtkCListRow * clist_row)
|
|
{
|
|
gint i;
|
|
|
|
for (i = 0; i < clist->columns; i++)
|
|
cell_empty (clist, clist_row, i);
|
|
|
|
if (clist_row->destroy)
|
|
clist_row->destroy (clist_row->data);
|
|
|
|
g_mem_chunk_free (clist->cell_mem_chunk, clist_row->cell);
|
|
g_mem_chunk_free (clist->row_mem_chunk, clist_row);
|
|
}
|
|
|
|
static void
|
|
cell_empty (GtkCList * clist,
|
|
GtkCListRow * clist_row,
|
|
gint column)
|
|
{
|
|
switch (clist_row->cell[column].type)
|
|
{
|
|
case GTK_CELL_EMPTY:
|
|
break;
|
|
|
|
case GTK_CELL_TEXT:
|
|
g_free (GTK_CELL_TEXT (clist_row->cell[column])->text);
|
|
break;
|
|
|
|
case GTK_CELL_PIXMAP:
|
|
gdk_pixmap_unref (GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap);
|
|
if (GTK_CELL_PIXMAP (clist_row->cell[column])->mask)
|
|
gdk_bitmap_unref (GTK_CELL_PIXMAP (clist_row->cell[column])->mask);
|
|
break;
|
|
|
|
case GTK_CELL_PIXTEXT:
|
|
g_free (GTK_CELL_PIXTEXT (clist_row->cell[column])->text);
|
|
gdk_pixmap_unref (GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap);
|
|
if (GTK_CELL_PIXTEXT (clist_row->cell[column])->mask)
|
|
gdk_bitmap_unref (GTK_CELL_PIXTEXT (clist_row->cell[column])->mask);
|
|
break;
|
|
|
|
case GTK_CELL_WIDGET:
|
|
/* unimplimented */
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
clist_row->cell[column].type = GTK_CELL_EMPTY;
|
|
}
|
|
|
|
static void
|
|
cell_set_text (GtkCList * clist,
|
|
GtkCListRow * clist_row,
|
|
gint column,
|
|
gchar * text)
|
|
{
|
|
cell_empty (clist, clist_row, column);
|
|
|
|
if (text)
|
|
{
|
|
clist_row->cell[column].type = GTK_CELL_TEXT;
|
|
GTK_CELL_TEXT (clist_row->cell[column])->text = g_strdup (text);
|
|
}
|
|
}
|
|
|
|
static void
|
|
cell_set_pixmap (GtkCList * clist,
|
|
GtkCListRow * clist_row,
|
|
gint column,
|
|
GdkPixmap * pixmap,
|
|
GdkBitmap * mask)
|
|
{
|
|
cell_empty (clist, clist_row, column);
|
|
|
|
if (pixmap)
|
|
{
|
|
clist_row->cell[column].type = GTK_CELL_PIXMAP;
|
|
GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap = pixmap;
|
|
/* We set the mask even if it is NULL */
|
|
GTK_CELL_PIXMAP (clist_row->cell[column])->mask = mask;
|
|
}
|
|
}
|
|
|
|
static void
|
|
cell_set_pixtext (GtkCList * clist,
|
|
GtkCListRow * clist_row,
|
|
gint column,
|
|
gchar * text,
|
|
guint8 spacing,
|
|
GdkPixmap * pixmap,
|
|
GdkBitmap * mask)
|
|
{
|
|
cell_empty (clist, clist_row, column);
|
|
|
|
if (text && pixmap)
|
|
{
|
|
clist_row->cell[column].type = GTK_CELL_PIXTEXT;
|
|
GTK_CELL_PIXTEXT (clist_row->cell[column])->text = g_strdup (text);
|
|
GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing = spacing;
|
|
GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap = pixmap;
|
|
GTK_CELL_PIXTEXT (clist_row->cell[column])->mask = mask;
|
|
}
|
|
}
|
|
|
|
/* Fill in data after widget is realized and has style */
|
|
|
|
static void
|
|
add_style_data (GtkCList * clist)
|
|
{
|
|
GtkWidget *widget;
|
|
|
|
widget = GTK_WIDGET(clist);
|
|
|
|
/* text properties */
|
|
if (!GTK_CLIST_ROW_HEIGHT_SET (clist))
|
|
{
|
|
clist->row_height = widget->style->font->ascent + widget->style->font->descent + 1;
|
|
clist->row_center_offset = widget->style->font->ascent + 1.5;
|
|
}
|
|
else
|
|
{
|
|
gint text_height;
|
|
text_height = clist->row_height - (GTK_WIDGET (clist)->style->font->ascent +
|
|
GTK_WIDGET (clist) ->style->font->descent + 1);
|
|
clist->row_center_offset = (text_height / 2) + GTK_WIDGET (clist)->style->font->ascent + 1.5;
|
|
}
|
|
|
|
/* Column widths */
|
|
}
|