32 #include <glib/gi18n.h>
33 #include <gdk/gdkkeysyms.h>
35 #include "gnc-cell-renderer-popup.h"
36 #include "gnc-cell-renderer-popup-entry.h"
47 static GtkCellEditable *
48 gcrp_start_editing (GtkCellRenderer *cell,
52 GdkRectangle *background_area,
53 GdkRectangle *cell_area,
54 GtkCellRendererState flags);
62 static void gcrp_get_size (GtkCellRenderer *cell,
64 GdkRectangle *cell_area,
69 static void gcrp_style_set (GtkWidget *widget,
72 static gboolean gcrp_key_press_event (GtkWidget *popup_window,
75 static gboolean gcrp_button_press_event (GtkWidget *widget,
76 GdkEventButton *event,
80 void gnc_marshal_VOID__STRING_INT_INT_INT_INT (GClosure *closure,
83 const GValue *param_values,
84 gpointer invocation_hint,
85 gpointer marshal_data);
88 static GtkCellRendererTextClass *parent_class;
89 static guint signals[LAST_SIGNAL];
91 #define GNC_CELL_RENDERER_POPUP_PATH "gnc-cell-renderer-popup-path"
94 gnc_cell_renderer_popup_get_type (
void)
96 static GType cell_text_type = 0;
98 if (!cell_text_type) {
99 static const GTypeInfo cell_text_info = {
103 (GClassInitFunc) gcrp_class_init,
108 (GInstanceInitFunc) gcrp_init,
111 cell_text_type = g_type_register_static (GTK_TYPE_CELL_RENDERER_TEXT,
112 "GncCellRendererPopup",
117 return cell_text_type;
123 popup->popup_window = gtk_window_new (GTK_WINDOW_POPUP);
125 popup->button_width = -1;
127 g_signal_connect (popup->popup_window,
128 "button-press-event",
129 G_CALLBACK (gcrp_button_press_event),
132 g_signal_connect (popup->popup_window,
134 G_CALLBACK (gcrp_key_press_event),
137 g_signal_connect (popup->popup_window,
139 G_CALLBACK (gcrp_style_set),
146 GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
148 parent_class = GTK_CELL_RENDERER_TEXT_CLASS (g_type_class_peek_parent (klass));
150 cell_class->start_editing = gcrp_start_editing;
151 cell_class->get_size = gcrp_get_size;
153 klass->show_popup = gcrp_show_popup;
154 klass->hide_popup = gcrp_hide_popup;
156 signals[SHOW_POPUP] = g_signal_new (
158 G_TYPE_FROM_CLASS (klass),
162 gnc_marshal_VOID__STRING_INT_INT_INT_INT,
170 signals[HIDE_POPUP] = g_signal_new (
172 G_TYPE_FROM_CLASS (klass),
176 g_cclosure_marshal_VOID__VOID,
181 gcrp_editing_done (GtkCellEditable *editable,
185 const gchar *new_text;
187 if (GNC_POPUP_ENTRY (editable)->editing_canceled ||
188 cell->editing_canceled) {
189 gtk_cell_renderer_stop_editing (GTK_CELL_RENDERER (cell), TRUE);
193 path = g_object_get_data (G_OBJECT (editable),
194 GNC_CELL_RENDERER_POPUP_PATH);
195 new_text = gnc_popup_entry_get_text (GNC_POPUP_ENTRY (editable));
197 gtk_cell_renderer_stop_editing (GTK_CELL_RENDERER (cell), FALSE);
199 g_signal_emit_by_name (cell,
206 gcrp_style_set (GtkWidget *widget,
211 popup->button_width = -1;
215 gcrp_grab_on_window (GdkWindow *window,
216 guint32 activate_time)
218 if ((gdk_pointer_grab (window, TRUE,
219 GDK_BUTTON_PRESS_MASK |
220 GDK_BUTTON_RELEASE_MASK |
221 GDK_POINTER_MOTION_MASK,
222 NULL, NULL, activate_time) == 0)) {
223 if (gdk_keyboard_grab (window, TRUE,
227 gdk_pointer_ungrab (activate_time);
245 gint screen_height, screen_width;
250 gtk_widget_realize (cell->popup_window);
255 gtk_window_move (GTK_WINDOW (cell->popup_window), -500, -500);
256 gtk_widget_show (cell->popup_window);
258 alloc = cell->popup_window->allocation;
263 button_height = y2 - y1;
265 screen_height = gdk_screen_height () - y;
266 screen_width = gdk_screen_width ();
269 if (alloc.height > screen_height) {
271 if (alloc.height > screen_height && y - button_height > screen_height) {
274 screen_height = y - button_height;
275 y -= (alloc.height + button_height);
285 if (x > screen_width) {
294 gtk_grab_add (cell->popup_window);
296 gtk_window_move (GTK_WINDOW (cell->popup_window), x, y);
297 gtk_widget_show (cell->popup_window);
299 gtk_widget_grab_focus (cell->focus_window);
301 gcrp_grab_on_window (cell->popup_window->window,
302 gtk_get_current_event_time ());
308 gtk_grab_remove (cell->popup_window);
309 gtk_widget_hide (cell->popup_window);
311 if (cell->editable) {
312 gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (cell->editable));
318 if (cell->editable) {
319 gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (cell->editable));
323 cell->editing_canceled = FALSE;
327 gcrp_arrow_clicked (GtkCellEditable *entry,
335 cell->editing_canceled = TRUE;
336 gnc_cell_renderer_popup_hide (cell);
340 path = g_object_get_data (G_OBJECT (entry),
341 GNC_CELL_RENDERER_POPUP_PATH);
348 if (!gcrp_grab_on_window (GTK_WIDGET (entry)->window,
349 gtk_get_current_event_time ())) {
353 gtk_editable_select_region (GTK_EDITABLE (GNC_POPUP_ENTRY (entry)->entry), 0, 0);
355 gdk_window_get_origin (GTK_WIDGET (entry)->window, &x, &y);
357 alloc = GTK_WIDGET (entry)->allocation;
359 g_signal_emit (cell, signals[SHOW_POPUP], 0,
367 static GtkCellEditable *
368 gcrp_start_editing (GtkCellRenderer *cell,
372 GdkRectangle *background_area,
373 GdkRectangle *cell_area,
374 GtkCellRendererState flags)
380 popup = GNC_CELL_RENDERER_POPUP (cell);
383 if (GTK_CELL_RENDERER_TEXT (popup)->editable == FALSE) {
387 editable = g_object_new (GNC_TYPE_POPUP_ENTRY, NULL);
389 text = GTK_CELL_RENDERER_TEXT (cell)->text;
390 popup->cell_text = text;
392 gnc_popup_entry_set_text (GNC_POPUP_ENTRY (editable), text ? text :
"");
394 g_object_set_data_full (G_OBJECT (editable),
395 GNC_CELL_RENDERER_POPUP_PATH,
399 gtk_widget_show (editable);
401 g_signal_connect (editable,
403 G_CALLBACK (gcrp_editing_done),
406 g_signal_connect (editable,
408 G_CALLBACK (gcrp_arrow_clicked),
411 popup->editable = editable;
413 g_object_add_weak_pointer (G_OBJECT (popup->editable),
414 (gpointer) &popup->editable);
416 return GTK_CELL_EDITABLE (editable);
420 gnc_cell_renderer_popup_new (
void)
422 return GTK_CELL_RENDERER (
423 g_object_new (gnc_cell_renderer_popup_get_type (), NULL));
429 g_return_if_fail (GNC_IS_CELL_RENDERER_POPUP (cell));
431 g_signal_emit (cell, signals[HIDE_POPUP], 0);
435 gcrp_get_size (GtkCellRenderer *cell,
437 GdkRectangle *cell_area,
445 popup = GNC_CELL_RENDERER_POPUP (cell);
447 if (GTK_CELL_RENDERER_CLASS (parent_class)->get_size) {
448 (* GTK_CELL_RENDERER_CLASS (parent_class)->get_size) (cell,
458 if (popup->button_width == -1) {
459 popup->button_width = gnc_popup_get_button_width ();
462 *width += popup->button_width;
466 gcrp_key_press_event (GtkWidget *popup_window,
470 if (event->keyval != GDK_Escape &&
471 event->keyval != GDK_Return &&
472 event->keyval != GDK_KP_Enter &&
473 event->keyval != GDK_ISO_Enter &&
474 event->keyval != GDK_3270_Enter) {
477 if (event->keyval == GDK_Escape) {
478 cell->editing_canceled = TRUE;
480 cell->editing_canceled = FALSE;
482 gnc_cell_renderer_popup_hide (cell);
488 gcrp_button_press_event (GtkWidget *widget,
489 GdkEventButton *event,
494 gint xoffset, yoffset;
498 if (event->button != 1) {
509 gdk_window_get_root_origin (widget->window,
513 xoffset += widget->allocation.x;
514 yoffset += widget->allocation.y;
516 alloc = popup->popup_window->allocation;
517 x1 = alloc.x + xoffset;
518 y1 = alloc.y + yoffset;
519 x2 = x1 + alloc.width;
520 y2 = y1 + alloc.height;
522 if (x > x1 && x < x2 && y > y1 && y < y2) {
526 popup->editing_canceled = TRUE;
527 gnc_cell_renderer_popup_hide (popup);
533 #define g_marshal_value_peek_int(v) (v)->data[0].v_int
534 #define g_marshal_value_peek_string(v) (v)->data[0].v_pointer
537 gnc_marshal_VOID__STRING_INT_INT_INT_INT (GClosure *closure,
538 GValue *return_value G_GNUC_UNUSED,
539 guint n_param_values,
540 const GValue *param_values,
541 gpointer invocation_hint G_GNUC_UNUSED,
542 gpointer marshal_data)
544 typedef void (*GMarshalFunc_VOID__STRING_INT_INT_INT_INT) (gpointer data1,
551 register GMarshalFunc_VOID__STRING_INT_INT_INT_INT callback;
552 register GCClosure *cc = (GCClosure*) closure;
553 register gpointer data1, data2;
555 g_return_if_fail (n_param_values == 6);
557 if (G_CCLOSURE_SWAP_DATA (closure))
559 data1 = closure->data;
560 data2 = g_value_peek_pointer (param_values + 0);
564 data1 = g_value_peek_pointer (param_values + 0);
565 data2 = closure->data;
567 callback = (GMarshalFunc_VOID__STRING_INT_INT_INT_INT) (marshal_data ? marshal_data : cc->callback);
570 g_marshal_value_peek_string (param_values + 1),
571 g_marshal_value_peek_int (param_values + 2),
572 g_marshal_value_peek_int (param_values + 3),
573 g_marshal_value_peek_int (param_values + 4),
574 g_marshal_value_peek_int (param_values + 5),