Updated Spanish translation
[evolution.git] / e-util / e-cell-popup.c
blobee7fc5497d22d9ac281e4647a0cb5c8eb05e8ea8
1 /*
2 * e-cell-popup.c: Popup cell renderer
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
11 * for more details.
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, see <http://www.gnu.org/licenses/>.
17 * Authors:
19 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
24 * ECellPopup - an abstract ECell class used to support popup selections like
25 * a GtkCombo widget. It contains a child ECell, e.g. an ECellText, but when
26 * selected it displays an arrow on the right edge which the user can click to
27 * show a popup. Subclasses implement the popup class function to show the
28 * popup.
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif
35 #include <gdk/gdkkeysyms.h>
37 #include "gal-a11y-e-cell-popup.h"
38 #include "gal-a11y-e-cell-registry.h"
40 #include "e-cell-popup.h"
41 #include "e-table-item.h"
42 #include <gtk/gtk.h>
44 #define E_CELL_POPUP_ARROW_SIZE 16
45 #define E_CELL_POPUP_ARROW_PAD 3
47 static void e_cell_popup_dispose (GObject *object);
49 static ECellView * ecp_new_view (ECell *ecell,
50 ETableModel *table_model,
51 void *e_table_item_view);
52 static void ecp_kill_view (ECellView *ecv);
53 static void ecp_realize (ECellView *ecv);
54 static void ecp_unrealize (ECellView *ecv);
55 static void ecp_draw (ECellView *ecv,
56 cairo_t *cr,
57 gint model_col,
58 gint view_col,
59 gint row,
60 ECellFlags flags,
61 gint x1,
62 gint y1,
63 gint x2,
64 gint y2);
65 static gint ecp_event (ECellView *ecv,
66 GdkEvent *event,
67 gint model_col,
68 gint view_col,
69 gint row,
70 ECellFlags flags,
71 ECellActions *actions);
72 static gint ecp_height (ECellView *ecv,
73 gint model_col,
74 gint view_col,
75 gint row);
76 static gpointer ecp_enter_edit (ECellView *ecv,
77 gint model_col,
78 gint view_col,
79 gint row);
80 static void ecp_leave_edit (ECellView *ecv,
81 gint model_col,
82 gint view_col,
83 gint row,
84 void *edit_context);
85 static void ecp_print (ECellView *ecv,
86 GtkPrintContext *context,
87 gint model_col,
88 gint view_col,
89 gint row,
90 gdouble width,
91 gdouble height);
92 static gdouble ecp_print_height (ECellView *ecv,
93 GtkPrintContext *context,
94 gint model_col,
95 gint view_col,
96 gint row,
97 gdouble width);
98 static gint ecp_max_width (ECellView *ecv,
99 gint model_col,
100 gint view_col);
101 static gchar *ecp_get_bg_color (ECellView *ecell_view, gint row);
103 static gint e_cell_popup_do_popup (ECellPopupView *ecp_view,
104 GdkEvent *event,
105 gint row,
106 gint model_col);
108 G_DEFINE_TYPE (ECellPopup, e_cell_popup, E_TYPE_CELL)
110 static void
111 e_cell_popup_class_init (ECellPopupClass *class)
113 ECellClass *ecc = E_CELL_CLASS (class);
115 G_OBJECT_CLASS (class)->dispose = e_cell_popup_dispose;
117 ecc->new_view = ecp_new_view;
118 ecc->kill_view = ecp_kill_view;
119 ecc->realize = ecp_realize;
120 ecc->unrealize = ecp_unrealize;
121 ecc->draw = ecp_draw;
122 ecc->event = ecp_event;
123 ecc->height = ecp_height;
124 ecc->enter_edit = ecp_enter_edit;
125 ecc->leave_edit = ecp_leave_edit;
126 ecc->print = ecp_print;
127 ecc->print_height = ecp_print_height;
128 ecc->max_width = ecp_max_width;
129 ecc->get_bg_color = ecp_get_bg_color;
131 gal_a11y_e_cell_registry_add_cell_type (
132 NULL, E_TYPE_CELL_POPUP,
133 gal_a11y_e_cell_popup_new);
136 static void
137 e_cell_popup_init (ECellPopup *ecp)
139 ecp->popup_shown = FALSE;
140 ecp->popup_model = NULL;
144 * e_cell_popup_new:
146 * Creates a new ECellPopup renderer.
148 * Returns: an ECellPopup object.
150 ECell *
151 e_cell_popup_new (void)
153 return g_object_new (E_TYPE_CELL_POPUP, NULL);
156 static void
157 e_cell_popup_dispose (GObject *object)
159 ECellPopup *ecp = E_CELL_POPUP (object);
161 if (ecp->child)
162 g_object_unref (ecp->child);
163 ecp->child = NULL;
165 G_OBJECT_CLASS (e_cell_popup_parent_class)->dispose (object);
169 * ECell::new_view method
171 static ECellView *
172 ecp_new_view (ECell *ecell,
173 ETableModel *table_model,
174 gpointer e_table_item_view)
176 ECellPopup *ecp = E_CELL_POPUP (ecell);
177 ECellPopupView *ecp_view;
179 /* We must have a child ECell before we create any views. */
180 g_return_val_if_fail (ecp->child != NULL, NULL);
182 ecp_view = g_new0 (ECellPopupView, 1);
184 ecp_view->cell_view.ecell = g_object_ref (ecell);
185 ecp_view->cell_view.e_table_model = table_model;
186 ecp_view->cell_view.e_table_item_view = e_table_item_view;
187 ecp_view->cell_view.kill_view_cb = NULL;
188 ecp_view->cell_view.kill_view_cb_data = NULL;
190 ecp_view->child_view = e_cell_new_view (
191 ecp->child, table_model,
192 e_table_item_view);
194 return (ECellView *) ecp_view;
198 * ECell::kill_view method
200 static void
201 ecp_kill_view (ECellView *ecv)
203 ECellPopupView *ecp_view = (ECellPopupView *) ecv;
205 if (E_IS_CELL_POPUP (ecp_view->cell_view.ecell)) {
206 ECellPopup *ecp = E_CELL_POPUP (ecp_view->cell_view.ecell);
208 if (ecp->popup_cell_view == ecp_view)
209 ecp->popup_cell_view = NULL;
212 g_clear_object (&ecp_view->cell_view.ecell);
214 if (ecp_view->cell_view.kill_view_cb)
215 ecp_view->cell_view.kill_view_cb (
216 ecv, ecp_view->cell_view.kill_view_cb_data);
218 if (ecp_view->cell_view.kill_view_cb_data)
219 g_list_free (ecp_view->cell_view.kill_view_cb_data);
221 if (ecp_view->child_view)
222 e_cell_kill_view (ecp_view->child_view);
224 g_free (ecp_view);
228 * ECell::realize method
230 static void
231 ecp_realize (ECellView *ecv)
233 ECellPopupView *ecp_view = (ECellPopupView *) ecv;
235 e_cell_realize (ecp_view->child_view);
237 if (E_CELL_CLASS (e_cell_popup_parent_class)->realize)
238 (* E_CELL_CLASS (e_cell_popup_parent_class)->realize) (ecv);
242 * ECell::unrealize method
244 static void
245 ecp_unrealize (ECellView *ecv)
247 ECellPopupView *ecp_view = (ECellPopupView *) ecv;
249 e_cell_unrealize (ecp_view->child_view);
251 if (E_CELL_CLASS (e_cell_popup_parent_class)->unrealize)
252 (* E_CELL_CLASS (e_cell_popup_parent_class)->unrealize) (ecv);
256 * ECell::draw method
258 static void
259 ecp_draw (ECellView *ecv,
260 cairo_t *cr,
261 gint model_col,
262 gint view_col,
263 gint row,
264 ECellFlags flags,
265 gint x1,
266 gint y1,
267 gint x2,
268 gint y2)
270 ECellPopup *ecp = E_CELL_POPUP (ecv->ecell);
271 ECellPopupView *ecp_view = (ECellPopupView *) ecv;
272 GtkWidget *canvas;
273 gboolean show_popup_arrow;
275 cairo_save (cr);
277 canvas = GTK_WIDGET (GNOME_CANVAS_ITEM (ecv->e_table_item_view)->canvas);
279 /* Display the popup arrow if we are the cursor cell, or the popup
280 * is shown for this cell. */
281 show_popup_arrow =
282 e_table_model_is_cell_editable (
283 ecv->e_table_model, model_col, row) &&
284 (flags & E_CELL_CURSOR ||
285 (ecp->popup_shown && ecp->popup_view_col == view_col
286 && ecp->popup_row == row
287 && ecp->popup_model == ((ECellView *) ecp_view)->e_table_model));
289 if (flags & E_CELL_CURSOR)
290 ecp->popup_arrow_shown = show_popup_arrow;
292 if (show_popup_arrow) {
293 GtkStyleContext *style_context;
294 gint arrow_x;
295 gint arrow_y;
296 gint arrow_size;
297 gint midpoint_y;
299 e_cell_draw (
300 ecp_view->child_view, cr, model_col,
301 view_col, row, flags,
302 x1, y1, x2 - E_CELL_POPUP_ARROW_SIZE, y2);
304 midpoint_y = y1 + ((y2 - y1 + 1) / 2);
306 arrow_x = x2 - E_CELL_POPUP_ARROW_SIZE;
307 arrow_y = midpoint_y - E_CELL_POPUP_ARROW_SIZE / 2;
308 arrow_size = E_CELL_POPUP_ARROW_SIZE;
310 style_context = gtk_widget_get_style_context (canvas);
312 gtk_style_context_save (style_context);
314 gtk_style_context_add_class (
315 style_context, GTK_STYLE_CLASS_CELL);
317 cairo_save (cr);
318 gtk_render_background (
319 style_context, cr,
320 (gdouble) arrow_x,
321 (gdouble) arrow_y,
322 (gdouble) arrow_size,
323 (gdouble) arrow_size);
324 cairo_restore (cr);
326 arrow_x += E_CELL_POPUP_ARROW_PAD;
327 arrow_y += E_CELL_POPUP_ARROW_PAD;
328 arrow_size -= (E_CELL_POPUP_ARROW_PAD * 2);
330 cairo_save (cr);
331 gtk_render_arrow (
332 style_context, cr, G_PI,
333 (gdouble) arrow_x,
334 (gdouble) arrow_y,
335 (gdouble) arrow_size);
336 cairo_restore (cr);
338 gtk_style_context_restore (style_context);
339 } else {
340 e_cell_draw (
341 ecp_view->child_view, cr, model_col,
342 view_col, row, flags, x1, y1, x2, y2);
345 cairo_restore (cr);
349 * ECell::event method
351 static gint
352 ecp_event (ECellView *ecv,
353 GdkEvent *event,
354 gint model_col,
355 gint view_col,
356 gint row,
357 ECellFlags flags,
358 ECellActions *actions)
360 ECellPopupView *ecp_view = (ECellPopupView *) ecv;
361 ECellPopup *ecp = E_CELL_POPUP (ecp_view->cell_view.ecell);
362 ETableItem *eti = E_TABLE_ITEM (ecv->e_table_item_view);
363 gint width;
365 switch (event->type) {
366 case GDK_BUTTON_PRESS:
367 if (e_table_model_is_cell_editable (ecv->e_table_model, model_col, row) &&
368 flags & E_CELL_CURSOR
369 && ecp->popup_arrow_shown) {
370 width = e_table_header_col_diff (
371 eti->header, view_col,
372 view_col + 1);
374 /* FIXME: The event coords seem to be relative to the
375 * text within the cell, so we have to add 4. */
376 if (event->button.x + 4 >= width - E_CELL_POPUP_ARROW_SIZE) {
377 return e_cell_popup_do_popup (ecp_view, event, row, view_col);
380 break;
381 case GDK_KEY_PRESS:
382 if (e_table_model_is_cell_editable (ecv->e_table_model, model_col, row) &&
383 event->key.state & GDK_MOD1_MASK
384 && event->key.keyval == GDK_KEY_Down) {
385 return e_cell_popup_do_popup (ecp_view, event, row, view_col);
387 break;
388 default:
389 break;
392 return e_cell_event (
393 ecp_view->child_view, event, model_col, view_col,
394 row, flags, actions);
398 * ECell::height method
400 static gint
401 ecp_height (ECellView *ecv,
402 gint model_col,
403 gint view_col,
404 gint row)
406 ECellPopupView *ecp_view = (ECellPopupView *) ecv;
408 return e_cell_height (ecp_view->child_view, model_col, view_col, row);
412 * ECellView::enter_edit method
414 static gpointer
415 ecp_enter_edit (ECellView *ecv,
416 gint model_col,
417 gint view_col,
418 gint row)
420 ECellPopupView *ecp_view = (ECellPopupView *) ecv;
422 return e_cell_enter_edit (ecp_view->child_view, model_col, view_col, row);
426 * ECellView::leave_edit method
428 static void
429 ecp_leave_edit (ECellView *ecv,
430 gint model_col,
431 gint view_col,
432 gint row,
433 gpointer edit_context)
435 ECellPopupView *ecp_view = (ECellPopupView *) ecv;
437 e_cell_leave_edit (
438 ecp_view->child_view, model_col, view_col, row,
439 edit_context);
442 static void
443 ecp_print (ECellView *ecv,
444 GtkPrintContext *context,
445 gint model_col,
446 gint view_col,
447 gint row,
448 gdouble width,
449 gdouble height)
451 ECellPopupView *ecp_view = (ECellPopupView *) ecv;
453 e_cell_print (
454 ecp_view->child_view, context, model_col, view_col, row,
455 width, height);
458 static gdouble
459 ecp_print_height (ECellView *ecv,
460 GtkPrintContext *context,
461 gint model_col,
462 gint view_col,
463 gint row,
464 gdouble width)
466 ECellPopupView *ecp_view = (ECellPopupView *) ecv;
468 return e_cell_print_height (
469 ecp_view->child_view, context, model_col,
470 view_col, row, width);
473 static gint
474 ecp_max_width (ECellView *ecv,
475 gint model_col,
476 gint view_col)
478 ECellPopupView *ecp_view = (ECellPopupView *) ecv;
480 return e_cell_max_width (ecp_view->child_view, model_col, view_col);
483 static gchar *
484 ecp_get_bg_color (ECellView *ecell_view,
485 gint row)
487 ECellPopupView *ecp_view = (ECellPopupView *) ecell_view;
489 return e_cell_get_bg_color (ecp_view->child_view, row);
492 ECell *
493 e_cell_popup_get_child (ECellPopup *ecp)
495 g_return_val_if_fail (E_IS_CELL_POPUP (ecp), NULL);
497 return ecp->child;
500 void
501 e_cell_popup_set_child (ECellPopup *ecp,
502 ECell *child)
504 g_return_if_fail (E_IS_CELL_POPUP (ecp));
506 if (ecp->child)
507 g_object_unref (ecp->child);
509 ecp->child = child;
510 g_object_ref (child);
513 static gint
514 e_cell_popup_do_popup (ECellPopupView *ecp_view,
515 GdkEvent *event,
516 gint row,
517 gint view_col)
519 ECellPopup *ecp = E_CELL_POPUP (ecp_view->cell_view.ecell);
520 gint (*popup_func) (ECellPopup *ecp, GdkEvent *event, gint row, gint view_col);
522 ecp->popup_cell_view = ecp_view;
524 popup_func = E_CELL_POPUP_CLASS (G_OBJECT_GET_CLASS (ecp))->popup;
526 ecp->popup_view_col = view_col;
527 ecp->popup_row = row;
528 ecp->popup_model = ((ECellView *) ecp_view)->e_table_model;
530 return popup_func ? popup_func (ecp, event, row, view_col) : FALSE;
533 /* This redraws the popup cell. Only use this if you know popup_view_col and
534 * popup_row are valid. */
535 void
536 e_cell_popup_queue_cell_redraw (ECellPopup *ecp)
538 ETableItem *eti;
540 g_return_if_fail (ecp->popup_cell_view != NULL);
542 eti = E_TABLE_ITEM (ecp->popup_cell_view->cell_view.e_table_item_view);
544 e_table_item_redraw_range (
545 eti, ecp->popup_view_col, ecp->popup_row,
546 ecp->popup_view_col, ecp->popup_row);
549 void
550 e_cell_popup_set_shown (ECellPopup *ecp,
551 gboolean shown)
553 ecp->popup_shown = shown;
554 e_cell_popup_queue_cell_redraw (ecp);