1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /*
3 * xap_TableWidget.cpp
4 * Copyright 2002 Joaquin Cuenca Abela
5 * Copyright 2016 Hubert Figuiere
6 *
7 * Authors:
8 * Joaquin Cuenca Abela (e98cuenc@yahoo.com)
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License, version 2, as published by the Free Software Foundation.
13 *
14 * This library is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 * 02110-1301 USA.
23 */
24
25 #include <stdio.h>
26 #include <stdlib.h>
27
28 #include <algorithm>
29
30 #include <gdk/gdkkeysyms.h>
31 #include <gdk/gdk.h>
32 #include <gtk/gtk.h>
33
34 #include "xap_Gtk2Compat.h"
35 #if GTK_CHECK_VERSION(3,0,0)
36 #include "xap_GtkStyle.h"
37 #endif
38 #include "xap_UnixTableWidget.h"
39 #include "ut_debugmsg.h"
40 #include "ut_assert.h"
41
42 /* NONE:UINT,UINT (/dev/stdin:1) */
43 static void
g_cclosure_user_marshal_VOID__UINT_UINT(GClosure * closure,GValue *,guint n_param_values,const GValue * param_values,gpointer,gpointer marshal_data)44 g_cclosure_user_marshal_VOID__UINT_UINT (GClosure *closure,
45 GValue * /*return_value*/,
46 guint n_param_values,
47 const GValue *param_values,
48 gpointer /*invocation_hint*/,
49 gpointer marshal_data)
50 {
51 typedef void (*GMarshalFunc_VOID__UINT_UINT) (gpointer data1,
52 guint arg_1,
53 guint arg_2,
54 gpointer data2);
55 register GMarshalFunc_VOID__UINT_UINT callback;
56 register GCClosure *cc = (GCClosure*) closure;
57 register gpointer data1, data2;
58
59 UT_return_if_fail (n_param_values == 3);
60 UT_DEBUGMSG(("IN AbiTable g_cclose_.. \n"));
61 if (G_CCLOSURE_SWAP_DATA (closure))
62 {
63 data1 = closure->data;
64 data2 = g_value_get_pointer (param_values + 0);
65 }
66 else
67 {
68 data1 = g_value_get_pointer (param_values + 0);
69 data2 = closure->data;
70 }
71 callback = (GMarshalFunc_VOID__UINT_UINT) (marshal_data ? marshal_data : cc->callback);
72 UT_DEBUGMSG(("Calling callback marshell data %p cc %p \n",callback,cc));
73
74 callback (data1,
75 g_value_get_uint (param_values + 1),
76 g_value_get_uint (param_values + 2),
77 data2);
78 }
79
80 enum
81 {
82 SELECTED,
83 LAST_SIGNAL
84 };
85
86 static gint abi_table_signals [LAST_SIGNAL] = { 0 };
87
88 static GtkWidgetClass *abi_table_parent_class;
89
90 /* ------------------- now the guts of AbiTable ---------------------- */
91
92 static const guint cell_width = 24;
93 static const guint cell_height = 24;
94 static const guint cell_spacing = 4;
95 static const guint init_rows = 0;
96 static const guint init_cols = 0;
97
98 static inline void
cells_to_pixels(guint cols,guint rows,guint * w,guint * h)99 cells_to_pixels(guint cols, guint rows, guint* w, guint* h)
100 {
101 UT_return_if_fail(w);
102 UT_return_if_fail(h);
103
104 *w = cell_width * cols + cell_spacing * (cols + 1);
105 *h = cell_height * rows + cell_spacing * (rows + 1);
106 }
107
108 static inline void
pixels_to_cells(guint w,guint h,guint * cols,guint * rows)109 pixels_to_cells(guint w, guint h, guint* cols, guint* rows)
110 {
111 UT_return_if_fail(cols);
112 UT_return_if_fail(rows);
113
114 *cols = w / (cell_width + cell_spacing) + 1;
115 *rows = h / (cell_height + cell_spacing) + 1;
116 }
117
118 static void
abi_table_resize(AbiTable * table)119 abi_table_resize(AbiTable* table)
120 {
121 guint width;
122 guint height;
123 char* text;
124 GtkRequisition size;
125
126 UT_return_if_fail(table);
127
128 if (table->selected_rows == 0 && table->selected_cols == 0)
129 text = g_strdup(table->szCancel);
130 else
131 {
132 text = g_strdup_printf("%d x %d %s", table->selected_rows, table->selected_cols, table->szTable);
133 }
134 cells_to_pixels(table->total_cols, table->total_rows, &width, &height);
135 gtk_widget_get_preferred_size(GTK_WIDGET(table->window_label), &size, NULL);
136
137 gtk_label_set_text(table->window_label, text);
138 gtk_window_resize(table->window, width + 1, height + size.height);
139
140 g_free(text);
141 }
142
143 extern "C" void
abi_table_set_selected(AbiTable * abi_table,guint rows,guint cols)144 abi_table_set_selected (AbiTable* abi_table, guint rows, guint cols)
145 {
146 UT_return_if_fail (abi_table);
147
148 abi_table->selected_rows = rows;
149 abi_table->selected_cols = cols;
150
151 abi_table_resize(abi_table);
152 }
153
154 extern "C" void
abi_table_get_selected(const AbiTable * abi_table,guint * rows,guint * cols)155 abi_table_get_selected (const AbiTable* abi_table, guint* rows, guint* cols)
156 {
157 UT_return_if_fail (abi_table);
158
159 if (rows)
160 *rows = abi_table->selected_rows;
161
162 if (cols)
163 *cols = abi_table->selected_cols;
164 }
165
166 extern "C" void
abi_table_set_max_size(AbiTable * abi_table,guint rows,guint cols)167 abi_table_set_max_size (AbiTable* abi_table, guint rows, guint cols)
168 {
169 UT_return_if_fail (abi_table);
170
171 abi_table->total_rows = rows;
172 abi_table->total_cols = cols;
173
174 abi_table_resize(abi_table);
175 }
176
177
178 extern "C" void
abi_table_set_labels(AbiTable * abi_table,const gchar * szTable,const gchar * szCancel)179 abi_table_set_labels(AbiTable* abi_table, const gchar * szTable, const gchar * szCancel)
180 {
181 if(abi_table->szTable)
182 g_free(abi_table->szTable);
183 abi_table->szTable = g_strdup(szTable);
184 if(abi_table->szCancel)
185 g_free(abi_table->szCancel);
186 abi_table->szCancel = g_strdup(szCancel);
187 }
188
189 extern "C" void
abi_table_get_max_size(const AbiTable * abi_table,guint * rows,guint * cols)190 abi_table_get_max_size (const AbiTable* abi_table, guint* rows, guint* cols)
191 {
192 UT_return_if_fail (abi_table);
193
194 if (rows)
195 *rows = abi_table->total_rows;
196
197 if (cols)
198 *cols = abi_table->total_cols;
199 }
200
201 static gboolean
202 #if GTK_CHECK_VERSION(3,0,0)
on_drawing_area_event(GtkWidget * area,cairo_t * cr,gpointer user_data)203 on_drawing_area_event (GtkWidget *area, cairo_t *cr, gpointer user_data)
204 #else
205 on_drawing_area_event (GtkWidget *area, GdkEventExpose *, gpointer user_data)
206 #endif
207 {
208 AbiTable* table = static_cast<AbiTable*>(user_data);
209
210 #if GTK_CHECK_VERSION(3,0,0)
211 if (!table || !table->style_context) {
212 return TRUE;
213 }
214 #endif
215
216 guint i;
217 guint j;
218 guint selected_rows = table->selected_rows;
219 guint selected_cols = table->selected_cols;
220 guint x;
221 guint y;
222
223 #if GTK_CHECK_VERSION(3,0,0)
224 GtkStyleContext* ctxt = gtk_widget_get_style_context(GTK_WIDGET(area));
225 gtk_style_context_save(ctxt);
226 gtk_style_context_set_state(ctxt, GTK_STATE_FLAG_FOCUSED);
227 #else
228 gdk_draw_rectangle (area->window,
229 area->style->bg_gc[GTK_STATE_NORMAL],
230 TRUE,
231 0, 0,
232 area->allocation.width,
233 area->allocation.height);
234 #endif
235
236 for (i = 0; i < table->total_rows; ++i) {
237 for (j = 0; j < table->total_cols; ++j) {
238 cells_to_pixels(j, i, &x, &y);
239
240 #if GTK_CHECK_VERSION(3,0,0)
241 if (i < selected_rows && j < selected_cols) {
242 gtk_style_context_set_state(table->style_context, GTK_STATE_FLAG_SELECTED);
243 } else {
244 gtk_style_context_set_state(table->style_context, GTK_STATE_FLAG_NORMAL);
245 }
246 gtk_render_background(table->style_context, cr, x + 1, y + 1,
247 cell_width - 1, cell_height - 1);
248
249 gtk_render_frame(ctxt, cr, x, y, cell_width, cell_height);
250 #else
251 gdk_draw_rectangle (area->window,
252 area->style->dark_gc[GTK_STATE_NORMAL],
253 FALSE,
254 x - 1, y - 1,
255 cell_width + 1,
256 cell_height + 1);
257 if (i < selected_rows && j < selected_cols) {
258 gdk_draw_rectangle (area->window,
259 table->selected_gc,
260 TRUE,
261 x, y,
262 cell_width,
263 cell_height);
264 }
265 else {
266 gdk_draw_rectangle (area->window,
267 area->style->white_gc,
268 TRUE,
269 x, y,
270 cell_width,
271 cell_height);
272 }
273 /* black border line */
274 gdk_draw_line (area->window,
275 area->style->black_gc,
276 area->allocation.width - 1, 0, area->allocation.width - 1, area->allocation.height - 1);
277 gdk_draw_line (area->window,
278 area->style->black_gc,
279 area->allocation.width - 1, area->allocation.height - 1, 0, area->allocation.height - 1);
280
281 /* dark border line */
282 gdk_draw_line (area->window,
283 area->style->dark_gc[GTK_STATE_NORMAL],
284 area->allocation.width - 2, 1, area->allocation.width - 2,
285 area->allocation.height - 2);
286 gdk_draw_line (area->window,
287 area->style->dark_gc[GTK_STATE_NORMAL],
288 area->allocation.width - 2, area->allocation.height - 2, 1,
289 area->allocation.height - 2);
290
291 /* ligth border line */
292 gdk_draw_line (area->window,
293 area->style->light_gc[GTK_STATE_NORMAL],
294 0, 0, area->allocation.width - 3, 0);
295 gdk_draw_line (area->window,
296 area->style->light_gc[GTK_STATE_NORMAL],
297 0, 0, 0, area->allocation.height - 2);
298 #endif
299 }
300 }
301 #if GTK_CHECK_VERSION(3,0,0)
302 gtk_style_context_restore(ctxt);
303 #endif
304
305 return TRUE;
306 }
307
308 static inline guint
my_max(guint a,guint b)309 my_max(guint a, guint b)
310 {
311 return a < b ? b : a;
312 }
313
314 static gboolean
on_motion_notify_event(GtkWidget * window,GdkEventMotion * ev,gpointer user_data)315 on_motion_notify_event (GtkWidget *window, GdkEventMotion *ev, gpointer user_data)
316 {
317 AbiTable* table = static_cast<AbiTable*>(user_data);
318 guint selected_cols;
319 guint selected_rows;
320
321 if (ev->x < 0 || ev->y < 0)
322 return TRUE;
323
324 pixels_to_cells(static_cast<guint>(ev->x), static_cast<guint>(ev->y), &selected_cols, &selected_rows);
325
326 if ((selected_cols != table->selected_cols) || (selected_rows != table->selected_rows))
327 {
328 /* grow or shrink the table widget as necessary */
329 table->selected_cols = selected_cols;
330 table->selected_rows = selected_rows;
331
332 if (table->selected_rows <= 0 || table->selected_cols <= 0)
333 table->selected_rows = table->selected_cols = 0;
334
335 table->total_rows = my_max(table->selected_rows + 1, 3);
336 table->total_cols = my_max(table->selected_cols + 1, 3);
337
338 abi_table_resize(table);
339 gtk_widget_queue_draw (window);
340 }
341
342 return TRUE;
343 }
344
345 static void
restart_widget(AbiTable * table)346 restart_widget (AbiTable *table)
347 {
348 table->selected_cols = init_cols;
349 table->selected_rows = init_rows;
350 table->total_cols = my_max(init_cols + 1, 5);
351 table->total_rows = my_max(init_rows + 1, 6);
352 g_signal_emit_by_name(table, "released");
353 gtk_widget_hide(GTK_WIDGET(table->window));
354 }
355
356 /*
357 * Fires signal "selected", and reset and hide the widget
358 */
359 static void
emit_selected(AbiTable * table)360 emit_selected (AbiTable *table)
361 {
362 gtk_widget_hide(GTK_WIDGET(table->window));
363
364 while (gtk_events_pending())
365 gtk_main_iteration();
366
367 if (table->selected_rows > 0 && table->selected_cols > 0)
368 g_signal_emit (G_OBJECT (table),
369 abi_table_signals [SELECTED], 0,
370 table->selected_rows, table->selected_cols);
371
372 restart_widget(table);
373 }
374
375 static gboolean
on_button_release_event(GtkWidget *,GdkEventButton * ev,gpointer user_data)376 on_button_release_event (GtkWidget *, GdkEventButton *ev, gpointer user_data)
377 {
378 AbiTable* table = static_cast<AbiTable*>(user_data);
379
380 /* Quick test to know if we're possibly over the button */
381 if (ev->y < 0.0 && ev->x >= 0.0)
382 {
383 GtkRequisition size;
384
385 gtk_widget_get_preferred_size(GTK_WIDGET(table), &size, NULL);
386
387 /* And now, precise and slightly slower test.
388 I wonder if the double test really matters from a speed pov */
389 if (-ev->y < size.height && ev->x < size.width)
390 return TRUE;
391 }
392
393 emit_selected(table);
394
395 return TRUE;
396 }
397
398 static gboolean
on_leave_event(GtkWidget * area,GdkEventCrossing * event,gpointer user_data)399 on_leave_event (GtkWidget *area,
400 GdkEventCrossing *event,
401 gpointer user_data)
402 {
403 AbiTable* table = static_cast<AbiTable*>(user_data);
404
405 if (gtk_widget_get_visible(GTK_WIDGET(table->window)) && (event->x < 0 || event->y < 0))
406 {
407 table->selected_rows = 0;
408 table->selected_cols = 0;
409 table->total_rows = my_max(table->selected_rows + 1, 3);
410 table->total_cols = my_max(table->selected_cols + 1, 3);
411
412 abi_table_resize(table);
413 gtk_widget_queue_draw (area);
414 }
415
416 return TRUE;
417 }
418
419 static gboolean
popup_grab_on_window(GdkWindow * window,guint32 activate_time)420 popup_grab_on_window (GdkWindow *window,
421 guint32 activate_time)
422 {
423 GdkEventMask emask = static_cast<GdkEventMask>(GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
424 GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK |
425 GDK_ENTER_NOTIFY_MASK) ;
426 if ((XAP_gdk_pointer_grab (window, FALSE,emask,
427 NULL, NULL, activate_time) == 0))
428 {
429 if (XAP_gdk_keyboard_grab (window, FALSE,
430 activate_time) == 0)
431 return TRUE;
432 else
433 {
434 XAP_gdk_pointer_ungrab (activate_time);
435 return FALSE;
436 }
437 }
438
439 return FALSE;
440 }
441
442 static void
on_pressed(GtkButton * button,gpointer user_data)443 on_pressed(GtkButton* button, gpointer user_data)
444 {
445 AbiTable* table = static_cast<AbiTable*>(user_data);
446 int left, top;
447 GtkAllocation alloc;
448
449 /* Temporarily grab pointer and keyboard on a window we know exists; we
450 * do this so that the grab (with owner events == TRUE) affects
451 * events generated when the window is mapped, such as enter
452 * notify events on subwidgets. If the grab fails, bail out.
453 */
454 if (!popup_grab_on_window (gtk_widget_get_window(GTK_WIDGET(button)),
455 gtk_get_current_event_time ()))
456 return;
457
458 auto toplevel = gtk_widget_get_toplevel(GTK_WIDGET(table));
459 gtk_window_set_transient_for(table->window, GTK_WINDOW(toplevel));
460 gdk_window_get_origin (gtk_widget_get_window(GTK_WIDGET(table)), &left, &top);
461 gtk_widget_get_allocation(GTK_WIDGET(table), &alloc);
462 gtk_window_move(table->window,
463 left + alloc.x, top + alloc.y + alloc.height);
464 abi_table_resize(table);
465
466 gtk_widget_show(GTK_WIDGET(table->window));
467 gtk_widget_grab_focus(GTK_WIDGET(table->window));
468
469 /* Now transfer our grabs to the popup window; this
470 * should always succeed.
471 */
472 popup_grab_on_window (gtk_widget_get_window(GTK_WIDGET(table->area)),
473 gtk_get_current_event_time ());
474 #if !GTK_CHECK_VERSION(3,0,0)
475 GdkColor selected_color = (GTK_WIDGET (button))->style->base[GTK_STATE_SELECTED];
476
477 /* leak */
478 table->selected_gc = gdk_gc_new(GTK_WIDGET(button)->window);
479 gdk_gc_set_rgb_fg_color(table->selected_gc, &selected_color);
480 #endif
481 }
482
483 gboolean
on_key_event(GtkWidget * widget,GdkEventKey * event,gpointer user_data)484 on_key_event(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
485 {
486 AbiTable* table = static_cast<AbiTable*>(user_data);
487 gboolean grew = FALSE;
488
489 switch (event->keyval)
490 {
491 case GDK_KEY_Up:
492 case GDK_KEY_KP_Up:
493 if (table->selected_rows > 0)
494 --table->selected_rows;
495 break;
496 case GDK_KEY_Down:
497 case GDK_KEY_KP_Down:
498 grew = TRUE;
499 ++table->selected_rows;
500 break;
501 case GDK_KEY_Left:
502 case GDK_KEY_KP_Left:
503 if (table->selected_cols > 0)
504 --table->selected_cols;
505 break;
506 case GDK_KEY_Right:
507 case GDK_KEY_KP_Right:
508 grew = TRUE;
509 ++table->selected_cols;
510 break;
511 case GDK_KEY_Escape:
512 restart_widget(table);
513 return TRUE;
514 case GDK_KEY_KP_Space:
515 case GDK_KEY_KP_Enter:
516 case GDK_KEY_space:
517 case GDK_KEY_3270_Enter:
518 case GDK_KEY_ISO_Enter:
519 case GDK_KEY_Return:
520 emit_selected(table);
521 return TRUE;
522 }
523
524 if(table->selected_rows == 0 || table->selected_cols == 0)
525 table->selected_rows = table->selected_cols = (grew ? 1 : 0) ;
526
527 table->total_rows = my_max(table->selected_rows + 1, 3);
528 table->total_cols = my_max(table->selected_cols + 1, 3);
529
530 abi_table_resize(table);
531 gtk_widget_queue_draw (widget);
532
533 return TRUE;
534 }
535
536
537 /* XPM */
538 static const char * widget_tb_insert_table_xpm[] = {
539 "24 24 32 1",
540 " c None",
541 ". c #000000",
542 "+ c #FFFFFF",
543 "@ c #B1B1B1",
544 "# c #BABABA",
545 "$ c #E4E4E4",
546 "% c #ECECEC",
547 "& c #A8A8A8",
548 "* c #ADADAD",
549 "= c #B9B9B9",
550 "- c #ABABAB",
551 "; c #B8B8B8",
552 "> c #B5B5B5",
553 ", c #AAAAAA",
554 "' c #858585",
555 ") c #828282",
556 "! c #707070",
557 "~ c #BCBCBC",
558 "{ c #A7A7A7",
559 "] c #8D8D8D",
560 "^ c #737373",
561 "/ c #ACACAC",
562 "( c #878787",
563 "_ c #747474",
564 ": c #A9A9A9",
565 "< c #E9E9E9",
566 "[ c #C3C3C3",
567 "} c #BFBFBF",
568 "| c #757575",
569 "1 c #7E7E7E",
570 "2 c #BBBBBB",
571 "3 c #A3A3A3",
572 " ",
573 " ",
574 " ",
575 " ................... ",
576 " .+++++@+++++#++++$. ",
577 " .+%%%%&%%%%%*%%%%=. ",
578 " .+%%%%-%%%%%-%%%%;. ",
579 " .>&,,&'&----)&---!. ",
580 " .+%%%%-%%%%%-%%%%~. ",
581 " .+%%%%-%%%%%-%%%%~. ",
582 " .+%%%%-%%%%%-%%%%~. ",
583 " .#{---'-----]*---^. ",
584 " .+%%%%-%%%%%-%%%%~. ",
585 " .+%%%%-%%%%%-%%%%;. ",
586 " .+%%%%-%%%%%-%%%%~. ",
587 " .;&--/(&{--&'&---_. ",
588 " .+%%%%-%%%%%-%%%%;. ",
589 " .+%%%%&%%%%%:%%%%~. ",
590 " .<[[[}|~~~~~1;~~23. ",
591 " ................... ",
592 " ",
593 " ",
594 " ",
595 " "};
596
597
598 static void
register_stock_icon(void)599 register_stock_icon(void)
600 {
601 static gboolean registered = FALSE;
602
603 if (!registered)
604 {
605 GdkPixbuf *pixbuf;
606 GtkIconFactory *factory;
607
608 static GtkStockItem items[] = {
609 { (gchar*)"abi-table-widget",
610 (gchar*)"_Table",
611 static_cast<GdkModifierType>(0), 0, NULL }
612 };
613
614 registered = TRUE;
615
616 /* Register our stock items */
617 gtk_stock_add (items, G_N_ELEMENTS (items));
618
619 /* Add our custom icon factory to the list of defaults */
620 factory = gtk_icon_factory_new ();
621 gtk_icon_factory_add_default (factory);
622
623 // Must be C cast
624 pixbuf = gdk_pixbuf_new_from_xpm_data((const char **)widget_tb_insert_table_xpm);
625
626 /* Register icon to accompany stock item */
627 if (pixbuf != NULL)
628 {
629 GtkIconSet *icon_set;
630
631 icon_set = gtk_icon_set_new_from_pixbuf (pixbuf);
632 gtk_icon_factory_add (factory, "abi-table-widget", icon_set);
633 gtk_icon_set_unref (icon_set);
634 g_object_unref (G_OBJECT (pixbuf));
635 }
636 else
637 {
638 UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
639 }
640
641 /* Drop our reference to the factory, GTK will hold a reference. */
642 g_object_unref (G_OBJECT (factory));
643 }
644 }
645
abi_table_set_icon(AbiTable * abi_table,GtkWidget * gtkImageIcon)646 void abi_table_set_icon(AbiTable* abi_table,GtkWidget * gtkImageIcon)
647 {
648 if(!GTK_IS_IMAGE(G_OBJECT(gtkImageIcon)))
649 return;
650 g_object_unref (G_OBJECT (abi_table->icon));
651 abi_table->icon = gtkImageIcon;
652 }
653
654 /* ------------------- and now the GObject part ---------------------- */
655
656 static void
abi_table_dispose(GObject * instance)657 abi_table_dispose (GObject *instance)
658 {
659 AbiTable* self = ABITABLE_WIDGET(instance);
660
661 // For some reason I get an alert
662 if(self->label) {
663 g_object_unref(self->label);
664 self->label = NULL;
665 }
666
667 if(self->szTable) {
668 g_free(self->szTable);
669 self->szTable = NULL;
670 }
671 if(self->szCancel) {
672 g_free(self->szCancel);
673 self->szCancel = NULL;
674 }
675
676 #if GTK_CHECK_VERSION(3,0,0)
677 g_clear_object(&self->style_context);
678 #endif
679
680 G_OBJECT_CLASS (abi_table_parent_class)->dispose (instance);
681 }
682
683 static void
abi_table_class_init(AbiTableClass * klass)684 abi_table_class_init (AbiTableClass *klass)
685 {
686 GtkWidgetClass *object_class = reinterpret_cast<GtkWidgetClass*>(klass);
687
688 G_OBJECT_CLASS(object_class)->dispose = abi_table_dispose;
689
690 abi_table_parent_class = static_cast<GtkWidgetClass *>(g_type_class_peek (GTK_TYPE_BUTTON));
691 abi_table_signals [SELECTED] =
692 g_signal_new ("selected",
693 G_OBJECT_CLASS_TYPE (object_class),
694 G_SIGNAL_RUN_LAST,
695 G_STRUCT_OFFSET (AbiTableClass, selected),
696 NULL, NULL,
697 g_cclosure_user_marshal_VOID__UINT_UINT,
698 G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
699 }
700
701 static void
abi_table_init(AbiTable * table)702 abi_table_init (AbiTable* table)
703 {
704 char* text = g_strdup_printf("%d x %d ", init_rows, init_cols);
705
706 register_stock_icon();
707
708 #if GTK_CHECK_VERSION(3,0,0)
709 table->style_context = XAP_GtkStyle_get_style(NULL, "GtkTreeView.view"); // "textview.view"
710 #endif
711
712 table->button_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
713
714 table->window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_POPUP));
715 table->window_vbox = GTK_BOX(gtk_box_new(GTK_ORIENTATION_VERTICAL, 0));
716
717 table->area = GTK_DRAWING_AREA(gtk_drawing_area_new());
718
719 table->handlers = 0;
720 table->window_label = GTK_LABEL(gtk_label_new(text));
721 g_free(text);
722 table->szTable = NULL;
723 table->szCancel = NULL;
724 gtk_container_add(GTK_CONTAINER(table->window), GTK_WIDGET(table->window_vbox));
725 gtk_box_pack_end(GTK_BOX(table->window_vbox), GTK_WIDGET(table->window_label), FALSE, FALSE, 0);
726 gtk_box_pack_end(GTK_BOX(table->window_vbox), GTK_WIDGET(table->area), TRUE, TRUE, 0);
727
728 gtk_widget_show_all(GTK_WIDGET(table->window_vbox));
729
730 table->selected_rows = init_rows;
731 table->selected_cols = init_cols;
732
733 table->total_rows = my_max(init_rows + 1, 5);
734 table->total_cols = my_max(init_cols + 1, 6);
735
736 abi_table_resize(table);
737
738 table->icon = NULL;
739 if (gtk_stock_lookup ("abi-table-widget", &table->stock_item))
740 {
741 table->label = gtk_label_new_with_mnemonic(table->stock_item.label);
742 table->icon = gtk_image_new_from_stock ("abi-table-widget", GTK_ICON_SIZE_LARGE_TOOLBAR);
743 gtk_widget_show(table->icon);
744 gtk_widget_show(table->label);
745 g_object_ref_sink(table->label);
746 //
747 // We actually never want this label in toolbar
748 // gtk_box_pack_end(GTK_BOX(table->button_box), table->label, FALSE, FALSE, 0);
749 gtk_box_pack_end(GTK_BOX(table->button_box), table->icon, FALSE, FALSE, 0);
750 UT_DEBUGMSG(("abi-table icon loaded %p !\n",table->icon));
751 }
752 else
753 {
754 /* it should not happen... */
755 UT_DEBUGMSG(("abi-table icon did not load !\n"));
756 UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
757 table->label = gtk_label_new_with_mnemonic("_Table");
758 g_object_ref_sink(table->label);
759 // gtk_box_pack_end(GTK_BOX(table->button_box), table->label, FALSE, FALSE, 0);
760 }
761
762 gtk_container_add(GTK_CONTAINER(table), GTK_WIDGET(table->button_box));
763
764 g_signal_connect(G_OBJECT(table), "pressed",
765 G_CALLBACK(on_pressed), static_cast<gpointer>(table));
766 #if GTK_CHECK_VERSION(3,0,0)
767 g_signal_connect(G_OBJECT(table->area), "draw",
768 G_CALLBACK(on_drawing_area_event), static_cast<gpointer>(table));
769 #else
770 g_signal_connect(G_OBJECT(table->area), "expose_event",
771 G_CALLBACK(on_drawing_area_event), static_cast<gpointer>(table));
772 #endif
773 g_signal_connect(G_OBJECT(table->area), "motion_notify_event",
774 G_CALLBACK(on_motion_notify_event), static_cast<gpointer>(table));
775 g_signal_connect(G_OBJECT(table->area), "button_release_event",
776 G_CALLBACK(on_button_release_event), static_cast<gpointer>(table));
777 g_signal_connect(G_OBJECT(table->area), "button_press_event",
778 G_CALLBACK(on_button_release_event), static_cast<gpointer>(table));
779 g_signal_connect(G_OBJECT(table->area), "leave_notify_event",
780 G_CALLBACK(on_leave_event), static_cast<gpointer>(table));
781 g_signal_connect(G_OBJECT(table->window), "key_press_event",
782 G_CALLBACK(on_key_event), static_cast<gpointer>(table));
783
784 gtk_widget_set_events (GTK_WIDGET(table->area), GDK_EXPOSURE_MASK
785 | GDK_LEAVE_NOTIFY_MASK
786 | GDK_BUTTON_PRESS_MASK
787 | GDK_BUTTON_RELEASE_MASK
788 | GDK_POINTER_MOTION_MASK
789 | GDK_KEY_PRESS_MASK
790 | GDK_KEY_RELEASE_MASK);
791
792 gtk_button_set_relief (GTK_BUTTON (table), GTK_RELIEF_NORMAL);
793 }
794
795
796 GType
abi_table_get_type(void)797 abi_table_get_type (void)
798 {
799 static GType type = 0;
800
801 if (!type)
802 {
803 static const GTypeInfo info =
804 {
805 sizeof (AbiTableClass),
806 NULL, /* base_init */
807 NULL, /* base_finalize */
808 reinterpret_cast<GClassInitFunc>(abi_table_class_init),
809 NULL, /* class_finalize */
810 NULL, /* class_data */
811 sizeof (AbiTable),
812 0, /* n_preallocs */
813 reinterpret_cast<GInstanceInitFunc>(abi_table_init),
814 NULL
815 };
816
817 type = g_type_register_static (GTK_TYPE_BUTTON, "AbiTable", &info, static_cast<GTypeFlags>(0));
818 }
819
820 return type;
821 }
822
823 GtkWidget*
abi_table_new(void)824 abi_table_new (void)
825 {
826 UT_DEBUGMSG(("COnstructing ABITABLE widget \n"));
827 return GTK_WIDGET (g_object_new (abi_table_get_type (), NULL));
828 }
829
830 /**
831 * abi_table_get_label:
832 * @abi_table: #AbiTable
833 *
834 * Returns: (transfer none): the label widget.
835 */
abi_table_get_label(AbiTable * abi_table)836 GtkWidget* abi_table_get_label(AbiTable* abi_table)
837 {
838 return abi_table->label;
839 }
840