diff options
Diffstat (limited to 'widgets/table/e-cell-spin-button.c')
-rw-r--r-- | widgets/table/e-cell-spin-button.c | 663 |
1 files changed, 663 insertions, 0 deletions
diff --git a/widgets/table/e-cell-spin-button.c b/widgets/table/e-cell-spin-button.c new file mode 100644 index 0000000000..ae28af3885 --- /dev/null +++ b/widgets/table/e-cell-spin-button.c @@ -0,0 +1,663 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2001 CodeFactory AB + * Copyright (C) 2001 Mikael Hallendal <micke@codefactory.se> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Mikael Hallendal <micke@codefactory.se> + * + * Celltype for drawing a spinbutton in a cell. + * + * Used ECellPopup by Damon Chaplin <damon@ximian.com> as base for + * buttondrawings. + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <gtk/gtksignal.h> +#include <gal/e-table/e-table-item.h> +#include <gal/e-table/e-table-model.h> +#include <gal/e-table/e-cell-float.h> +#include <gal/e-table/e-cell-number.h> +#include <gal/util/e-util.h> +#include "e-cell-spin-button.h" + +#define E_CELL_SPIN_BUTTON_ARROW_WIDTH 16 +#define PARENT_TYPE e_cell_get_type () + +static void e_cell_spin_button_class_init (GtkObjectClass *klass); +static void e_cell_spin_button_init (GtkObject *object); + +static void ecsb_destroy (GtkObject *object); + +/* ECell Functions */ +static ECellView * ecsb_new_view (ECell *ecell, + ETableModel *etm, + void *eti_view); +static void ecsb_realize (ECellView *ecv); +static void ecsb_kill_view (ECellView *ecv); +static void ecsb_unrealize (ECellView *ecv); +static void ecsb_draw (ECellView *ecv, + GdkDrawable *drawable, + int model_col, + int view_col, + int row, + ECellFlags flags, + int x1, + int y1, + int x2, + int y2); + +static gint ecsb_event (ECellView *ecv, + GdkEvent *event, + int model_col, + int view_col, + int row, + ECellFlags flags, + ECellActions *actions); + +static gint ecsb_height (ECellView *ecv, + int model_col, + int view_col, + int row); + +static void * ecsb_enter_edit (ECellView *ecv, + int model_col, + int view_col, + int row); + +static void ecsb_leave_edit (ECellView *ecv, + int model_col, + int view_col, + int row, + void *context); +static void ecsb_focus (ECellView *ecell_view, + int model_col, + int view_col, + int row, + int x1, + int y1, + int x2, + int y2); +static void ecsb_unfocus (ECellView *ecell_view); + +static void ecsb_show_tooltip (ECellView *ecv, + int model_col, + int view_col, + int row, + int col_width, + ETableTooltip *tooltip); + +typedef struct { + ECellView cell_view; + + ECellView *child_view; +} ECellSpinButtonView; + +enum { + STEP, + LAST_SIGNAL +}; + +static gint signals[LAST_SIGNAL] = { 0 }; +static ECell *parent_class; + +static void +e_cell_spin_button_class_init (GtkObjectClass *klass) +{ + ECellClass *ecc = (ECellClass *) klass; + ECellSpinButtonClass *ecsbc = (ECellSpinButtonClass *) klass; + + klass->destroy = ecsb_destroy; + + ecc->realize = ecsb_realize; + ecc->unrealize = ecsb_unrealize; + ecc->new_view = ecsb_new_view; + ecc->kill_view = ecsb_kill_view; + ecc->draw = ecsb_draw; + ecc->event = ecsb_event; + ecc->height = ecsb_height; + ecc->enter_edit = ecsb_enter_edit; + ecc->leave_edit = ecsb_leave_edit; + ecc->focus = ecsb_focus; + ecc->unfocus = ecsb_unfocus; ecc->print = NULL; + ecc->print_height = NULL; + ecc->max_width = NULL; + ecc->show_tooltip = ecsb_show_tooltip; + + ecsbc->step = NULL; + + parent_class = gtk_type_class (E_CELL_TYPE); + + signals[STEP] = + gtk_signal_new ("step", + GTK_RUN_LAST, + klass->type, + GTK_SIGNAL_OFFSET (ECellSpinButtonClass, step), + e_marshal_NONE__POINTER_INT_INT_INT, + GTK_TYPE_NONE, + 4, GTK_TYPE_POINTER, GTK_TYPE_INT, + GTK_TYPE_INT, GTK_TYPE_INT); + + gtk_object_class_add_signals (klass, signals, LAST_SIGNAL); +} + +static void +e_cell_spin_button_init (GtkObject *object) +{ + ECellSpinButton *ecsb; + + g_return_if_fail (object != NULL); + g_return_if_fail (M_IS_CELL_SPIN_BUTTON (object)); + + ecsb = E_CELL_SPIN_BUTTON (object); + + ecsb->up_pressed = FALSE; + ecsb->down_pressed = FALSE; +} + +static ECellView * +ecsb_new_view (ECell *ecell, + ETableModel *etm, + void *eti_view) +{ + ECellSpinButton *ecsb = E_CELL_SPIN_BUTTON (ecell); + ECellSpinButtonView *ecsb_view; + + g_return_val_if_fail (ecsb->child != NULL, NULL); + + ecsb_view = g_new0 (ECellSpinButtonView, 1); + + ecsb_view->cell_view.ecell = ecell; + ecsb_view->cell_view.e_table_model = etm; + ecsb_view->cell_view.e_table_item_view = eti_view; + + ecsb_view->child_view = e_cell_new_view (ecsb->child, etm, eti_view); + + return (ECellView *) ecsb_view; +} + +static void +ecsb_realize (ECellView *ecv) +{ + ECellSpinButtonView *ecsb_view; + + g_return_if_fail (ecv != NULL); + + ecsb_view = (ECellSpinButtonView *) ecv; + + e_cell_realize (ecsb_view->child_view); +} + +static void +ecsb_kill_view (ECellView *ecv) +{ + ECellSpinButtonView *ecsb_view; + + g_return_if_fail (ecv != NULL); + + ecsb_view = (ECellSpinButtonView *) ecv; + + if (ecsb_view->child_view) { + e_cell_kill_view (ecsb_view->child_view); + } + + g_free (ecsb_view); +} + +static void +ecsb_unrealize (ECellView *ecv) +{ + ECellSpinButtonView *ecsb_view; + + g_return_if_fail (ecv != NULL); + + ecsb_view = (ECellSpinButtonView *) ecv; + + e_cell_unrealize (ecsb_view->child_view); +} + +static void +ecsb_draw (ECellView *ecv, + GdkDrawable *drawable, + int model_col, + int view_col, + int row, + ECellFlags flags, + int x1, + int y1, + int x2, + int y2) +{ + ECellSpinButton *ecsb; + ECellSpinButtonView *ecsb_view; + ETableItem *eti; + GtkWidget *canvas; + GtkShadowType shadow = GTK_SHADOW_OUT; + GdkRectangle rect; + + g_return_if_fail (ecv != NULL); + + ecsb_view = (ECellSpinButtonView *) ecv; + ecsb = E_CELL_SPIN_BUTTON (ecsb_view->cell_view.ecell); + + eti = E_TABLE_ITEM (ecsb_view->cell_view.e_table_item_view); + canvas = GTK_WIDGET (GNOME_CANVAS_ITEM (eti)->canvas); + + if (eti->editing_col == view_col && + eti->editing_row == row) { + + /* Draw child (Whats shown under the buttons) */ + e_cell_draw (ecsb_view->child_view, + drawable, model_col, view_col, + row, flags, + x1, y1, + x2 - E_CELL_SPIN_BUTTON_ARROW_WIDTH, y2); + + /* Draw down-arrow */ + rect.x = x2 - E_CELL_SPIN_BUTTON_ARROW_WIDTH; + rect.y = y1 + (y2 - y1) / 2; + rect.width = E_CELL_SPIN_BUTTON_ARROW_WIDTH; + rect.height = (y2 - y1) / 2; + + if (ecsb->down_pressed) { + shadow = GTK_SHADOW_IN; + } else { + shadow = GTK_SHADOW_OUT; + } + + gtk_paint_box (canvas->style, drawable, + GTK_STATE_NORMAL, shadow, + &rect, canvas, "ecellspinbutton_down", + rect.x, rect.y, rect.width, rect.height); + + gtk_paint_arrow (canvas->style, drawable, + GTK_STATE_NORMAL, shadow, + &rect, canvas, NULL, + GTK_ARROW_DOWN, TRUE, + rect.x, + rect.y, + rect.width, + rect.height); + + /* Draw up-arrow */ + rect.y = y1; + + if (ecsb->up_pressed) { + shadow = GTK_SHADOW_IN; + } else { + shadow = GTK_SHADOW_OUT; + } + + gtk_paint_box (canvas->style, drawable, + GTK_STATE_NORMAL, shadow, + &rect, canvas, "ecellspinbutton_up", + rect.x, rect.y, rect.width, rect.height); + + gtk_paint_arrow (canvas->style, drawable, + GTK_STATE_NORMAL, shadow, + &rect, canvas, NULL, + GTK_ARROW_UP, TRUE, + rect.x, + rect.y, + rect.width, + rect.height); + } else { + /* Draw child */ + e_cell_draw (ecsb_view->child_view, + drawable, model_col, view_col, + row, flags, + x1, y1, + x2, y2); + } +} + +static gint +ecsb_event (ECellView *ecv, + GdkEvent *event, + int model_col, + int view_col, + int row, + ECellFlags flags, + ECellActions *actions) +{ + ECellSpinButton *ecsb; + ECellSpinButtonClass *ecsb_class; + ECellSpinButtonView *ecsb_view; + ETableItem *eti; + gint height, width; + + g_return_val_if_fail (ecv != NULL, FALSE); + + ecsb_view = (ECellSpinButtonView *) ecv; + ecsb = E_CELL_SPIN_BUTTON (ecsb_view->cell_view.ecell); + ecsb_class = E_CELL_SPIN_BUTTON_CLASS (GTK_OBJECT(ecsb)->klass); + eti = E_TABLE_ITEM (ecsb_view->cell_view.e_table_item_view); + + switch (event->type) { + case GDK_BUTTON_PRESS: + if (eti->editing_col == view_col && + eti->editing_row == row) { + width = e_table_header_col_diff (eti->header, + view_col, + view_col + 1); + height = e_table_item_row_diff (eti, row, row + 1); + + /* Check if inside a button */ + if (event->button.x >= width - E_CELL_SPIN_BUTTON_ARROW_WIDTH) { + /* Yep, which one? */ + if (event->button.y <= height / 2) { + ecsb->up_pressed = TRUE; + gtk_signal_emit (GTK_OBJECT(ecsb), + signals[STEP], + ecv, + STEP_UP, + view_col, + row); + } else { + ecsb->down_pressed = TRUE; + gtk_signal_emit (GTK_OBJECT(ecsb), + signals[STEP], + ecv, + STEP_DOWN, + view_col, + row); + } + + e_table_item_redraw_range (eti, + view_col, + row, + view_col, + row); + + } + } + + break; + case GDK_BUTTON_RELEASE: + ecsb->up_pressed = FALSE; + ecsb->down_pressed = FALSE; + e_table_item_redraw_range (eti, + view_col, + row, + view_col, + row); + break; + case GDK_KEY_PRESS: + break; + default: + break; + } + + return e_cell_event (ecsb_view->child_view, event, model_col, + view_col, row, flags, actions); +} + +static gint +ecsb_height (ECellView *ecv, + int model_col, + int view_col, + int row) +{ + ECellSpinButtonView *ecsb_view; + + g_return_val_if_fail (ecv != NULL, -1); + + ecsb_view = (ECellSpinButtonView *) ecv; + + return e_cell_height (ecsb_view->child_view, model_col, view_col, row); +} + +static void * +ecsb_enter_edit (ECellView *ecv, + int model_col, + int view_col, + int row) +{ + ECellSpinButtonView *ecsb_view; + + g_return_val_if_fail (ecv != NULL, NULL); + + ecsb_view = (ECellSpinButtonView *) ecv; + + return e_cell_enter_edit (ecsb_view->child_view, model_col, + view_col, row); +} + + +static void +ecsb_leave_edit (ECellView *ecv, + int model_col, + int view_col, + int row, + void *context) +{ + ECellSpinButtonView *ecsb_view; + + g_return_if_fail (ecv != NULL); + + ecsb_view = (ECellSpinButtonView *) ecv; + + e_cell_leave_edit (ecsb_view->child_view, model_col, view_col, + row, context); +} + +static void +ecsb_focus (ECellView *ecell_view, + int model_col, + int view_col, + int row, + int x1, + int y1, + int x2, + int y2) +{ + ECellClass *klass; + ECellSpinButtonView *ecsb_view; + + ecsb_view = (ECellSpinButtonView *) ecell_view; + + klass = E_CELL_CLASS (GTK_OBJECT (ecell_view->ecell)->klass); + + if (klass->focus) { + klass->focus (ecell_view, model_col, view_col, row, + x1, y1, x2, y2); + } +} + +static void +ecsb_unfocus (ECellView *ecell_view) +{ + ECellClass *klass; + ECellSpinButtonView *ecsb_view; + + ecsb_view = (ECellSpinButtonView *) ecell_view; + klass = E_CELL_CLASS (GTK_OBJECT (ecell_view->ecell)->klass); + + if (klass->unfocus) { + klass->unfocus (ecell_view); + } + +} + +static void +ecsb_show_tooltip (ECellView *ecv, + int model_col, + int view_col, + int row, + int col_width, + ETableTooltip *tooltip) +{ + ECellSpinButtonView *ecsb_view; + + g_return_if_fail (ecv != NULL); + + ecsb_view = (ECellSpinButtonView *) ecv; + + e_cell_show_tooltip (ecsb_view->child_view, model_col, view_col, + row, col_width, tooltip); +} + +static void +ecsb_destroy (GtkObject *object) +{ + ECellSpinButton *mcsp; + + g_return_if_fail (object != NULL); + g_return_if_fail (M_IS_CELL_SPIN_BUTTON (object)); + + mcsp = E_CELL_SPIN_BUTTON (object); + + GTK_OBJECT_CLASS (parent_class)->destroy (object); +} + +ECell * +e_cell_spin_button_new (gint min, + gint max, + gint step, + ECell *child_cell) +{ + ECellSpinButton *ecsb; + + ecsb = gtk_type_new (E_CELL_SPIN_BUTTON_TYPE); + + if (!child_cell) { + child_cell = e_cell_number_new (NULL, + GTK_JUSTIFY_LEFT); + + gtk_signal_connect (GTK_OBJECT (ecsb), "step", + e_cell_spin_button_step, + NULL); + } + + ecsb->child = child_cell; + ecsb->min.i = min; + ecsb->max.i = max; + ecsb->step.i = step; + + return E_CELL (ecsb); +} + +ECell * +e_cell_spin_button_new_float (gfloat min, + gfloat max, + gfloat step, + ECell *child_cell) +{ + ECellSpinButton *ecsb; + + ecsb = gtk_type_new (E_CELL_SPIN_BUTTON_TYPE); + + if (!child_cell) { + child_cell = e_cell_float_new (NULL, GTK_JUSTIFY_LEFT); + gtk_signal_connect (GTK_OBJECT (ecsb), "step", + e_cell_spin_button_step_float, + NULL); + } + + ecsb->child = child_cell; + ecsb->min.f = min; + ecsb->max.f = max; + ecsb->step.f = step; + + return E_CELL (ecsb); +} + +void +e_cell_spin_button_step (ECellSpinButton *ecsb, + ECellView *ecv, + ECellSpinButtonStep direction, + gint col, + gint row) +{ + ECellSpinButtonView *ecsb_view; + + ETableModel *etm; + gint value; + gint new_value; + + g_return_if_fail (ecsb != NULL); + g_return_if_fail (M_IS_CELL_SPIN_BUTTON (ecsb)); + g_return_if_fail (ecv != NULL); + + ecsb_view = (ECellSpinButtonView *) ecv; + etm = ecsb_view->cell_view.e_table_model; + + value = GPOINTER_TO_INT (e_table_model_value_at (etm, col, row)); + new_value = value; + + switch (direction) { + case STEP_UP: + new_value = CLAMP (value + ecsb->step.i, + ecsb->min.i, ecsb->max.i); + break; + case STEP_DOWN: + new_value = CLAMP (value - ecsb->step.i, + ecsb->min.i, ecsb->max.i); + break; + default: + break; + }; + + e_table_model_set_value_at (etm, col, row, GINT_TO_POINTER(new_value)); +} + +void +e_cell_spin_button_step_float (ECellSpinButton *ecsb, + ECellView *ecv, + ECellSpinButtonStep direction, + gint col, + gint row) +{ + ECellSpinButtonView *ecsb_view; + + ETableModel *etm; + gfloat value; + gfloat new_value; + + g_return_if_fail (ecsb != NULL); + g_return_if_fail (M_IS_CELL_SPIN_BUTTON (ecsb)); + g_return_if_fail (ecv != NULL); + + ecsb_view = (ECellSpinButtonView *) ecv; + etm = ecsb_view->cell_view.e_table_model; + + value = *(gfloat *) e_table_model_value_at (etm, col, row); + + switch (direction) { + case STEP_UP: + new_value = CLAMP (value + ecsb->step.f, + ecsb->min.f, ecsb->max.f); + break; + case STEP_DOWN: + new_value = CLAMP (value - ecsb->step.f, + ecsb->min.f, ecsb->max.f); + break; + default: + break; + }; + + e_table_model_set_value_at (etm, col, row, &new_value); +} + +E_MAKE_TYPE (e_cell_spin_button, "ECellSpinButton", ECellSpinButton, + e_cell_spin_button_class_init, e_cell_spin_button_init, + PARENT_TYPE); + |