1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
4 * sheet-object-widget.c: SheetObject wrappers for simple gtk widgets.
6 * Copyright (C) 2000-2006 Jody Goldberg (jody@gnome.org)
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
23 #include <gnumeric-config.h>
24 #include <glib/gi18n-lib.h>
26 #include "application.h"
27 #include "sheet-object-widget-impl.h"
28 #include "widgets/gnm-radiobutton.h"
30 #include "gnumeric-simple-canvas.h"
33 #include "dependent.h"
34 #include "sheet-control-gui.h"
35 #include "sheet-object-impl.h"
37 #include "parse-util.h"
40 #include "selection.h"
46 #include "gnumeric-expr-entry.h"
47 #include "dialogs/dialogs.h"
48 #include "dialogs/help.h"
51 #include "gnm-format.h"
52 #include "number-match.h"
54 #include <goffice/goffice.h>
56 #include <gsf/gsf-impl-utils.h>
57 #include <libxml/globals.h>
58 #include <gdk/gdkkeysyms.h>
63 #define CXML2C(s) ((char const *)(s))
64 #define CC2XML(s) ((xmlChar const *)(s))
66 static inline gboolean
67 attr_eq (const xmlChar
*a
, const char *s
)
69 return !strcmp (CXML2C (a
), s
);
72 /****************************************************************************/
75 cb_so_get_ref (GnmDependent
*dep
, G_GNUC_UNUSED SheetObject
*so
, gpointer user
)
77 GnmDependent
**pdep
= user
;
82 so_get_ref (SheetObject
const *so
, GnmCellRef
*res
, gboolean force_sheet
)
85 GnmDependent
*dep
= NULL
;
87 g_return_val_if_fail (so
!= NULL
, NULL
);
89 /* Let's hope there's just one. */
90 sheet_object_foreach_dep ((SheetObject
*)so
, cb_so_get_ref
, &dep
);
91 g_return_val_if_fail (dep
, NULL
);
93 if (dep
->texpr
== NULL
)
96 target
= gnm_expr_top_get_range (dep
->texpr
);
100 *res
= target
->v_range
.cell
.a
;
101 value_release (target
);
103 if (force_sheet
&& res
->sheet
== NULL
)
104 res
->sheet
= sheet_object_get_sheet (so
);
109 cb_so_clear_sheet (GnmDependent
*dep
, G_GNUC_UNUSED SheetObject
*so
, G_GNUC_UNUSED gpointer user
)
111 if (dependent_is_linked (dep
))
112 dependent_unlink (dep
);
117 so_clear_sheet (SheetObject
*so
)
119 /* Note: This implements sheet_object_clear_sheet. */
120 sheet_object_foreach_dep (so
, cb_so_clear_sheet
, NULL
);
125 get_goc_widget (SheetObjectView
*view
)
127 GocGroup
*group
= GOC_GROUP (view
);
129 if (group
== NULL
|| group
->children
== NULL
)
132 return GOC_WIDGET (group
->children
->data
);
136 so_widget_view_set_bounds (SheetObjectView
*sov
, double const *coords
, gboolean visible
)
138 GocItem
*view
= GOC_ITEM (sov
);
139 double scale
= goc_canvas_get_pixels_per_unit (view
->canvas
);
140 double left
= MIN (coords
[0], coords
[2]) / scale
;
141 double top
= MIN (coords
[1], coords
[3]) / scale
;
142 double width
= (fabs (coords
[2] - coords
[0]) + 1.) / scale
;
143 double height
= (fabs (coords
[3] - coords
[1]) + 1.) / scale
;
145 /* We only need the next check for frames, but it doesn't hurt otherwise. */
150 /* NOTE : far point is EXCLUDED so we add 1 */
151 goc_widget_set_bounds (get_goc_widget (sov
),
152 left
, top
, width
, height
);
153 goc_item_show (view
);
155 goc_item_hide (view
);
159 so_widget_view_get_window (GocItem
*item
)
161 GocGroup
*group
= GOC_GROUP (item
);
162 return goc_item_get_window (GOC_ITEM (group
->children
->data
));
166 so_widget_view_class_init (SheetObjectViewClass
*sov_klass
)
168 GocItemClass
*item_klass
= (GocItemClass
*) sov_klass
;
169 sov_klass
->set_bounds
= so_widget_view_set_bounds
;
170 item_klass
->get_window
= so_widget_view_get_window
;
173 static GSF_CLASS (SOWidgetView
, so_widget_view
,
174 so_widget_view_class_init
, NULL
,
177 /****************************************************************************/
179 #define SHEET_OBJECT_CONFIG_KEY "sheet-object-config-dialog"
181 #define GNM_SOW_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GNM_SOW_TYPE, SheetObjectWidgetClass))
182 #define SOW_CLASS(so) (GNM_SOW_CLASS (G_OBJECT_GET_CLASS(so)))
184 #define SOW_MAKE_TYPE(n1, n2, fn_config, fn_set_sheet, fn_clear_sheet, fn_foreach_dep, \
185 fn_copy, fn_write_sax, fn_prep_sax_parser, \
186 fn_get_property, fn_set_property, \
187 fn_draw_cairo, class_init_code) \
190 sheet_widget_ ## n1 ## _class_init (GObjectClass *object_class) \
192 SheetObjectWidgetClass *sow_class = GNM_SOW_CLASS (object_class); \
193 SheetObjectClass *so_class = GNM_SO_CLASS (object_class); \
194 object_class->finalize = &sheet_widget_ ## n1 ## _finalize; \
195 object_class->set_property = fn_set_property; \
196 object_class->get_property = fn_get_property; \
197 so_class->user_config = fn_config; \
198 so_class->interactive = TRUE; \
199 so_class->assign_to_sheet = fn_set_sheet; \
200 so_class->remove_from_sheet = fn_clear_sheet; \
201 so_class->foreach_dep = fn_foreach_dep; \
202 so_class->copy = fn_copy; \
203 so_class->write_xml_sax = fn_write_sax; \
204 so_class->prep_sax_parser = fn_prep_sax_parser; \
205 so_class->draw_cairo = fn_draw_cairo; \
206 sow_class->create_widget = &sheet_widget_ ## n1 ## _create_widget; \
207 { class_init_code; } \
210 GSF_CLASS (SheetWidget ## n2, sheet_widget_ ## n1, \
211 &sheet_widget_ ## n1 ## _class_init, \
212 &sheet_widget_ ## n1 ## _init, \
220 SheetObjectClass parent_class
;
221 GtkWidget
*(*create_widget
)(SheetObjectWidget
*);
222 } SheetObjectWidgetClass
;
224 static GObjectClass
*sheet_object_widget_class
= NULL
;
227 sow_create_widget (SheetObjectWidget
*sow
)
229 GtkWidget
*w
= SOW_CLASS(sow
)->create_widget (sow
);
230 GtkStyleContext
*context
= gtk_widget_get_style_context (w
);
231 gtk_style_context_add_class (context
, "sheet-object");
236 sheet_widget_draw_cairo (SheetObject
const *so
, cairo_t
*cr
,
237 double width
, double height
)
239 /* This is the default for so widgets without their own method */
240 /* See bugs #705638 and #705640 */
241 if (NULL
!= gdk_screen_get_default ()) {
242 GtkWidget
*win
= gtk_offscreen_window_new ();
243 GtkWidget
*w
= sow_create_widget (GNM_SOW (so
));
245 gtk_container_add (GTK_CONTAINER (win
), w
);
246 gtk_widget_set_size_request (w
, width
, height
);
247 gtk_widget_show_all (win
);
248 gtk_container_propagate_draw (GTK_CONTAINER (win
), w
, cr
);
249 gtk_widget_destroy (win
);
251 g_warning (_("Because of GTK bug #705640, a sheet object widget is not being printed."));
255 sax_write_dep (GsfXMLOut
*output
, GnmDependent
const *dep
, char const *id
,
256 GnmConventions
const *convs
)
258 if (dep
->texpr
!= NULL
) {
262 parse_pos_init_dep (&pos
, dep
);
263 val
= gnm_expr_top_as_string (dep
->texpr
, &pos
, convs
);
264 gsf_xml_out_add_cstr (output
, id
, val
);
270 sax_read_dep (xmlChar
const * const *attrs
, char const *name
,
271 GnmDependent
*dep
, GsfXMLIn
*xin
, GnmConventions
const *convs
)
273 g_return_val_if_fail (attrs
!= NULL
, FALSE
);
274 g_return_val_if_fail (attrs
[0] != NULL
, FALSE
);
275 g_return_val_if_fail (attrs
[1] != NULL
, FALSE
);
277 if (!attr_eq (attrs
[0], name
))
281 if (attrs
[1] != NULL
&& *attrs
[1] != '\0') {
284 parse_pos_init_sheet (&pp
, gnm_xml_in_cur_sheet (xin
));
285 dep
->texpr
= gnm_expr_parse_str (CXML2C (attrs
[1]), &pp
,
286 GNM_EXPR_PARSE_DEFAULT
,
294 static SheetObjectView
*
295 sheet_object_widget_new_view (SheetObject
*so
, SheetObjectViewContainer
*container
)
297 GtkWidget
*view_widget
= sow_create_widget (GNM_SOW (so
));
298 GocItem
*view_item
= goc_item_new (
299 gnm_pane_object_group (GNM_PANE (container
)),
300 so_widget_view_get_type (),
302 goc_item_new (GOC_GROUP (view_item
),
304 "widget", view_widget
,
306 /* g_warning ("%p is widget for so %p", (void *)view_widget, (void *)so);*/
307 gtk_widget_show_all (view_widget
);
308 goc_item_hide (view_item
);
309 gnm_pane_widget_register (so
, view_widget
, view_item
);
310 return gnm_pane_object_register (so
, view_item
, TRUE
);
314 sheet_object_widget_class_init (GObjectClass
*object_class
)
316 SheetObjectClass
*so_class
= GNM_SO_CLASS (object_class
);
317 SheetObjectWidgetClass
*sow_class
= GNM_SOW_CLASS (object_class
);
319 sheet_object_widget_class
= G_OBJECT_CLASS (object_class
);
321 /* SheetObject class method overrides */
322 so_class
->new_view
= sheet_object_widget_new_view
;
323 so_class
->rubber_band_directly
= TRUE
;
324 so_class
->draw_cairo
= sheet_widget_draw_cairo
;
326 sow_class
->create_widget
= NULL
;
330 sheet_object_widget_init (SheetObjectWidget
*sow
)
332 SheetObject
*so
= GNM_SO (sow
);
333 so
->flags
|= SHEET_OBJECT_CAN_PRESS
;
336 GSF_CLASS (SheetObjectWidget
, sheet_object_widget
,
337 sheet_object_widget_class_init
,
338 sheet_object_widget_init
,
341 static WorkbookControl
*
342 widget_wbc (GtkWidget
*widget
)
344 return scg_wbc (GNM_SIMPLE_CANVAS (gtk_widget_get_ancestor (widget
, GNM_SIMPLE_CANVAS_TYPE
))->scg
);
348 /****************************************************************************/
349 #define GNM_SOW_FRAME(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNM_SOW_FRAME_TYPE, SheetWidgetFrame))
351 SheetObjectWidget sow
;
354 typedef SheetObjectWidgetClass SheetWidgetFrameClass
;
362 sheet_widget_frame_get_property (GObject
*obj
, guint param_id
,
363 GValue
*value
, GParamSpec
*pspec
)
365 SheetWidgetFrame
*swf
= GNM_SOW_FRAME (obj
);
369 g_value_set_string (value
, swf
->label
);
372 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj
, param_id
, pspec
);
378 sheet_widget_frame_set_property (GObject
*obj
, guint param_id
,
379 GValue
const *value
, GParamSpec
*pspec
)
381 SheetWidgetFrame
*swf
= GNM_SOW_FRAME (obj
);
385 sheet_widget_frame_set_label (GNM_SO (swf
),
386 g_value_get_string (value
));
389 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj
, param_id
, pspec
);
396 sheet_widget_frame_init_full (SheetWidgetFrame
*swf
, char const *text
)
398 swf
->label
= g_strdup (text
);
402 sheet_widget_frame_init (SheetWidgetFrame
*swf
)
404 sheet_widget_frame_init_full (swf
, _("Frame"));
408 sheet_widget_frame_finalize (GObject
*obj
)
410 SheetWidgetFrame
*swf
= GNM_SOW_FRAME (obj
);
415 sheet_object_widget_class
->finalize (obj
);
419 sheet_widget_frame_create_widget (SheetObjectWidget
*sow
)
421 GtkWidget
*widget
= gtk_event_box_new (),
422 *frame
= gtk_frame_new (GNM_SOW_FRAME (sow
)->label
);
423 gtk_container_add (GTK_CONTAINER (widget
), frame
);
424 gtk_event_box_set_visible_window (GTK_EVENT_BOX (widget
), FALSE
);
429 sheet_widget_frame_copy (SheetObject
*dst
, SheetObject
const *src
)
431 sheet_widget_frame_init_full (GNM_SOW_FRAME (dst
),
432 GNM_SOW_FRAME (src
)->label
);
436 sheet_widget_frame_write_xml_sax (SheetObject
const *so
, GsfXMLOut
*output
,
437 G_GNUC_UNUSED GnmConventions
const *convs
)
439 SheetWidgetFrame
const *swf
= GNM_SOW_FRAME (so
);
440 gsf_xml_out_add_cstr (output
, "Label", swf
->label
);
444 sheet_widget_frame_prep_sax_parser (SheetObject
*so
, G_GNUC_UNUSED GsfXMLIn
*xin
,
445 xmlChar
const **attrs
,
446 G_GNUC_UNUSED GnmConventions
const *convs
)
448 SheetWidgetFrame
*swf
= GNM_SOW_FRAME (so
);
449 for (; attrs
!= NULL
&& attrs
[0] && attrs
[1] ; attrs
+= 2)
450 if (attr_eq (attrs
[0], "Label")) {
452 swf
->label
= g_strdup (CXML2C (attrs
[1]));
461 GtkWidget
*old_focus
;
464 SheetWidgetFrame
*swf
;
469 cb_frame_config_destroy (FrameConfigState
*state
)
471 g_return_if_fail (state
!= NULL
);
473 g_free (state
->old_label
);
474 state
->old_label
= NULL
;
475 state
->dialog
= NULL
;
480 cb_frame_config_ok_clicked (G_GNUC_UNUSED GtkWidget
*button
, FrameConfigState
*state
)
482 gchar
const *text
= gtk_entry_get_text(GTK_ENTRY(state
->label
));
484 cmd_so_set_frame_label (GNM_WBC (state
->wbcg
),
486 g_strdup (state
->old_label
), g_strdup (text
));
487 gtk_widget_destroy (state
->dialog
);
491 sheet_widget_frame_set_label (SheetObject
*so
, char const* str
)
493 SheetWidgetFrame
*swf
= GNM_SOW_FRAME (so
);
496 str
= str
? str
: "";
498 if (go_str_compare (str
, swf
->label
) == 0)
502 swf
->label
= g_strdup (str
);
504 for (ptr
= swf
->sow
.so
.realized_list
; ptr
!= NULL
; ptr
= ptr
->next
) {
505 SheetObjectView
*view
= ptr
->data
;
506 GocWidget
*item
= get_goc_widget (view
);
507 GList
*children
= gtk_container_get_children (GTK_CONTAINER (item
->widget
));
508 gtk_frame_set_label (GTK_FRAME (children
->data
), str
);
509 g_list_free (children
);
514 cb_frame_config_cancel_clicked (G_GNUC_UNUSED GtkWidget
*button
, FrameConfigState
*state
)
516 sheet_widget_frame_set_label (GNM_SO (state
->swf
), state
->old_label
);
518 gtk_widget_destroy (state
->dialog
);
522 cb_frame_label_changed (GtkWidget
*entry
, FrameConfigState
*state
)
526 text
= gtk_entry_get_text(GTK_ENTRY(entry
));
527 sheet_widget_frame_set_label (GNM_SO (state
->swf
), text
);
531 sheet_widget_frame_user_config (SheetObject
*so
, SheetControl
*sc
)
533 SheetWidgetFrame
*swf
= GNM_SOW_FRAME (so
);
534 WBCGtk
*wbcg
= scg_wbcg (GNM_SCG (sc
));
535 FrameConfigState
*state
;
538 g_return_if_fail (swf
!= NULL
);
540 /* Only pop up one copy per workbook */
541 if (gnm_dialog_raise_if_exists (wbcg
, SHEET_OBJECT_CONFIG_KEY
))
544 gui
= gnm_gtk_builder_load ("res:ui/so-frame.ui", NULL
, GO_CMD_CONTEXT (wbcg
));
547 state
= g_new (FrameConfigState
, 1);
550 state
->sheet
= sc_sheet (sc
);
551 state
->old_focus
= NULL
;
552 state
->old_label
= g_strdup(swf
->label
);
553 state
->dialog
= go_gtk_builder_get_widget (gui
, "so_frame");
555 state
->label
= go_gtk_builder_get_widget (gui
, "entry");
556 gtk_entry_set_text (GTK_ENTRY(state
->label
), swf
->label
);
557 gtk_editable_select_region (GTK_EDITABLE(state
->label
), 0, -1);
558 gnm_editable_enters (GTK_WINDOW (state
->dialog
),
559 GTK_WIDGET (state
->label
));
561 g_signal_connect (G_OBJECT(state
->label
),
563 G_CALLBACK (cb_frame_label_changed
), state
);
564 g_signal_connect (G_OBJECT (go_gtk_builder_get_widget (gui
,
567 G_CALLBACK (cb_frame_config_ok_clicked
), state
);
568 g_signal_connect (G_OBJECT (go_gtk_builder_get_widget (gui
,
571 G_CALLBACK (cb_frame_config_cancel_clicked
), state
);
573 gnm_init_help_button (
574 go_gtk_builder_get_widget (gui
, "help_button"),
575 GNUMERIC_HELP_LINK_SO_FRAME
);
578 gnm_keyed_dialog (state
->wbcg
, GTK_WINDOW (state
->dialog
),
579 SHEET_OBJECT_CONFIG_KEY
);
581 wbc_gtk_attach_guru (state
->wbcg
, state
->dialog
);
582 g_object_set_data_full (G_OBJECT (state
->dialog
),
583 "state", state
, (GDestroyNotify
) cb_frame_config_destroy
);
584 g_object_unref (gui
);
586 gtk_widget_show (state
->dialog
);
589 static PangoFontDescription
*
592 // Note: Under gnumeric, we get a proper font using GtkStyleContext.
593 // Under ssconvert, we try GSettings.
594 // The 'sans 10' is just insurance
596 PangoFontDescription
*desc
;
600 if (gdk_screen_get_default ()) {
601 // Without a default screen, the following will crash
603 GtkStyleContext
*style
= gtk_style_context_new ();
604 GtkWidgetPath
*path
= gtk_widget_path_new ();
606 gtk_style_context_set_path (style
, path
);
607 gtk_widget_path_unref (path
);
609 gtk_style_context_get (style
, GTK_STATE_FLAG_NORMAL
,
610 GTK_STYLE_PROPERTY_FONT
, &desc
, NULL
);
611 g_object_unref (style
);
613 desc
= pango_font_description_new ();
615 mask
= pango_font_description_get_set_fields (desc
);
616 if ((mask
& PANGO_FONT_MASK_SIZE
) != 0)
617 size
= pango_font_description_get_size (desc
);
619 if (gnm_debug_flag ("so-font")) {
620 char *s
= pango_font_description_to_string (desc
);
621 g_printerr ("from GtkStyleContext font=\"%s\", family set = %i,"
622 " size set = %i, size = %i\n",
623 s
, ((mask
& PANGO_FONT_MASK_FAMILY
) != 0),
624 ((mask
& PANGO_FONT_MASK_SIZE
) != 0), size
);
628 if ((mask
& PANGO_FONT_MASK_FAMILY
) == 0 || size
== 0) {
629 /* Trying gsettings */
630 GSettings
*set
= g_settings_new ("org.gnome.desktop.interface");
631 char *font_name
= g_settings_get_string (set
, "font-name");
632 if (font_name
!= NULL
) {
633 pango_font_description_free (desc
);
634 desc
= pango_font_description_from_string (font_name
);
636 mask
= pango_font_description_get_set_fields (desc
);
637 if ((mask
& PANGO_FONT_MASK_SIZE
) != 0)
638 size
= pango_font_description_get_size (desc
);
641 if (gnm_debug_flag ("so-font")) {
642 char *s
= pango_font_description_to_string (desc
);
643 g_printerr ("from GSettings: font=\"%s\", family set = %i,"
644 " size set = %i, size = %i\n",
645 s
, ((mask
& PANGO_FONT_MASK_FAMILY
) != 0),
646 ((mask
& PANGO_FONT_MASK_SIZE
) != 0), size
);
652 if ((mask
& PANGO_FONT_MASK_FAMILY
) == 0 || size
== 0) {
653 pango_font_description_free (desc
);
654 desc
= pango_font_description_from_string ("sans 10");
655 if (gnm_debug_flag ("so-font"))
656 g_printerr ("Using \"sans 10\" instead.\n");
663 draw_cairo_text (cairo_t
*cr
, char const *text
, int *pwidth
, int *pheight
,
664 gboolean centered_v
, gboolean centered_h
, gboolean single
, gint highlight_n
, gboolean scale
)
666 PangoLayout
*layout
= pango_cairo_create_layout (cr
);
667 double const scale_h
= 72. / gnm_app_display_dpi_get (TRUE
);
668 double const scale_v
= 72. / gnm_app_display_dpi_get (FALSE
);
669 PangoFontDescription
*desc
= get_font ();
672 pango_context_set_font_description
673 (pango_layout_get_context (layout
), desc
);
674 pango_layout_set_spacing (layout
, 3 * PANGO_SCALE
);
675 pango_layout_set_single_paragraph_mode (layout
, single
);
676 pango_layout_set_text (layout
, text
, -1);
677 pango_layout_get_pixel_size (layout
, &width
, &height
);
679 cairo_scale (cr
, scale_h
, scale_v
);
681 if (scale
&& pwidth
!= NULL
&& pheight
!= NULL
) {
682 double sc_x
= ((double) *pwidth
)/(width
* scale_h
);
683 double sc_y
= ((double) *pheight
)/(height
* scale_v
);
684 double sc
= MIN(sc_x
, sc_y
);
687 cairo_scale (cr
, sc
, sc
);
691 cairo_rel_move_to (cr
, 0., 0.5 - ((double)height
)/2.);
693 cairo_rel_move_to (cr
, 0.5 - ((double)width
)/2., 0.);
694 if (highlight_n
> 0 && pheight
!= NULL
&& pwidth
!= NULL
) {
695 PangoLayoutIter
*pliter
;
696 gboolean got_line
= TRUE
;
698 pliter
= pango_layout_get_iter (layout
);
699 for (i
= 1; i
< highlight_n
; i
++)
700 got_line
= pango_layout_iter_next_line (pliter
);
704 double dy0
= 0, dy1
= 0;
705 pango_layout_iter_get_line_yrange (pliter
, &y0
, &y1
);
706 dy0
= y0
/ (double)PANGO_SCALE
;
707 dy1
= y1
/ (double)PANGO_SCALE
;
709 if (dy1
> (*pheight
- 4)/scale_v
)
710 cairo_translate (cr
, 0, (*pheight
- 4)/scale_v
- dy1
);
713 cairo_rectangle (cr
, -4/scale_h
, dy0
,
714 *pwidth
/scale_h
, dy1
- dy0
);
715 cairo_set_source_rgb(cr
, 0.8, 0.8, 0.8);
718 pango_layout_iter_free (pliter
);
719 cairo_set_source_rgb(cr
, 0, 0, 0);
721 pango_cairo_show_layout (cr
, layout
);
722 pango_font_description_free (desc
);
723 g_object_unref (layout
);
726 *pwidth
= width
* scale_h
;
728 *pheight
= height
* scale_v
;
732 sheet_widget_frame_draw_cairo (SheetObject
const *so
, cairo_t
*cr
,
733 double width
, double height
)
735 SheetWidgetFrame
*swf
= GNM_SOW_FRAME (so
);
737 int theight
= 0, twidth
= 0;
739 cairo_move_to (cr
, 10, 0);
742 cairo_set_source_rgb(cr
, 0.0, 0.0, 0.0);
743 draw_cairo_text (cr
, swf
->label
, &twidth
, &theight
, FALSE
, FALSE
, TRUE
, 0, FALSE
);
746 cairo_set_line_width (cr
, 1);
747 cairo_set_line_cap (cr
, CAIRO_LINE_CAP_ROUND
);
748 cairo_set_source_rgb(cr
, 0.5, 0.5, 0.5);
750 cairo_move_to (cr
, 6, theight
/2);
751 cairo_line_to (cr
, 0, theight
/2);
752 cairo_line_to (cr
, 0, height
);
753 cairo_line_to (cr
, width
, height
);
754 cairo_line_to (cr
, width
, theight
/2);
755 cairo_line_to (cr
, 14 + twidth
, theight
/2);
758 cairo_set_source_rgb(cr
, 0.8, 0.8, 0.8);
760 cairo_move_to (cr
, 6, theight
/2 + 1);
761 cairo_line_to (cr
, 1, theight
/2 + 1);
762 cairo_line_to (cr
, 1, height
- 1);
763 cairo_line_to (cr
, width
- 1, height
- 1);
764 cairo_line_to (cr
, width
- 1, theight
/2 + 1);
765 cairo_line_to (cr
, 14 + twidth
, theight
/2 + 1);
772 SOW_MAKE_TYPE (frame
, Frame
,
773 sheet_widget_frame_user_config
,
777 sheet_widget_frame_copy
,
778 sheet_widget_frame_write_xml_sax
,
779 sheet_widget_frame_prep_sax_parser
,
780 sheet_widget_frame_get_property
,
781 sheet_widget_frame_set_property
,
782 sheet_widget_frame_draw_cairo
,
784 g_object_class_install_property
785 (object_class
, SOF_PROP_TEXT
,
786 g_param_spec_string ("text", NULL
, NULL
, NULL
,
787 GSF_PARAM_STATIC
| G_PARAM_READWRITE
));
790 /****************************************************************************/
791 #define GNM_SOW_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNM_SOW_BUTTON_TYPE, SheetWidgetButton))
792 #define DEP_TO_BUTTON(d_ptr) (SheetWidgetButton *)(((char *)d_ptr) - G_STRUCT_OFFSET(SheetWidgetButton, dep))
794 SheetObjectWidget sow
;
798 PangoAttrList
*markup
;
801 typedef SheetObjectWidgetClass SheetWidgetButtonClass
;
810 sheet_widget_button_get_property (GObject
*obj
, guint param_id
,
811 GValue
*value
, GParamSpec
*pspec
)
813 SheetWidgetButton
*swb
= GNM_SOW_BUTTON (obj
);
817 g_value_set_string (value
, swb
->label
);
819 case SOB_PROP_MARKUP
:
820 g_value_set_boxed (value
, NULL
); /* swb->markup */
823 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj
, param_id
, pspec
);
829 sheet_widget_button_set_property (GObject
*obj
, guint param_id
,
830 GValue
const *value
, GParamSpec
*pspec
)
832 SheetWidgetButton
*swb
= GNM_SOW_BUTTON (obj
);
836 sheet_widget_button_set_label (GNM_SO (swb
),
837 g_value_get_string (value
));
839 case SOB_PROP_MARKUP
:
841 sheet_widget_button_set_markup (GNM_SO (swb
),
842 g_value_peek_pointer (value
));
846 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj
, param_id
, pspec
);
852 button_eval (GnmDependent
*dep
)
856 gboolean err
, result
;
858 v
= gnm_expr_top_eval (dep
->texpr
, eval_pos_init_dep (&pos
, dep
),
859 GNM_EXPR_EVAL_SCALAR_NON_EMPTY
);
860 result
= value_get_as_bool (v
, &err
);
863 SheetWidgetButton
*swb
= DEP_TO_BUTTON(dep
);
870 button_debug_name (GnmDependent
const *dep
, GString
*target
)
872 g_string_append_printf (target
, "Button%p", (void *)dep
);
875 static DEPENDENT_MAKE_TYPE (button
, NULL
)
878 sheet_widget_button_init_full (SheetWidgetButton
*swb
,
879 GnmCellRef
const *ref
,
881 PangoAttrList
*markup
)
883 SheetObject
*so
= GNM_SO (swb
);
885 so
->flags
&= ~SHEET_OBJECT_PRINT
;
886 swb
->label
= g_strdup (text
);
887 swb
->markup
= markup
;
889 swb
->dep
.sheet
= NULL
;
890 swb
->dep
.flags
= button_get_dep_type ();
891 swb
->dep
.texpr
= (ref
!= NULL
)
892 ? gnm_expr_top_new (gnm_expr_new_cellref (ref
))
894 if (markup
) pango_attr_list_ref (markup
);
898 sheet_widget_button_init (SheetWidgetButton
*swb
)
900 sheet_widget_button_init_full (swb
, NULL
, _("Button"), NULL
);
904 sheet_widget_button_finalize (GObject
*obj
)
906 SheetWidgetButton
*swb
= GNM_SOW_BUTTON (obj
);
912 pango_attr_list_unref (swb
->markup
);
916 dependent_set_expr (&swb
->dep
, NULL
);
918 sheet_object_widget_class
->finalize (obj
);
922 cb_button_pressed (GtkToggleButton
*button
, SheetWidgetButton
*swb
)
928 if (so_get_ref (GNM_SO (swb
), &ref
, TRUE
) != NULL
) {
929 cmd_so_set_value (widget_wbc (GTK_WIDGET (button
)),
931 &ref
, value_new_bool (TRUE
),
932 sheet_object_get_sheet (GNM_SO (swb
)));
937 cb_button_released (GtkToggleButton
*button
, SheetWidgetButton
*swb
)
943 if (so_get_ref (GNM_SO (swb
), &ref
, TRUE
) != NULL
) {
944 cmd_so_set_value (widget_wbc (GTK_WIDGET (button
)),
945 _("Released Button"),
946 &ref
, value_new_bool (FALSE
),
947 sheet_object_get_sheet (GNM_SO (swb
)));
952 sheet_widget_button_create_widget (SheetObjectWidget
*sow
)
954 SheetWidgetButton
*swb
= GNM_SOW_BUTTON (sow
);
955 GtkWidget
*w
= gtk_button_new_with_label (swb
->label
);
956 gtk_widget_set_can_focus (w
, FALSE
);
957 gtk_label_set_attributes (GTK_LABEL (gtk_bin_get_child (GTK_BIN (w
))),
959 g_signal_connect (G_OBJECT (w
),
961 G_CALLBACK (cb_button_pressed
), swb
);
962 g_signal_connect (G_OBJECT (w
),
964 G_CALLBACK (cb_button_released
), swb
);
969 sheet_widget_button_copy (SheetObject
*dst
, SheetObject
const *src
)
971 SheetWidgetButton
const *src_swb
= GNM_SOW_BUTTON (src
);
972 SheetWidgetButton
*dst_swb
= GNM_SOW_BUTTON (dst
);
974 sheet_widget_button_init_full (dst_swb
,
975 so_get_ref (src
, &ref
, FALSE
),
978 dst_swb
->value
= src_swb
->value
;
983 GnmExprEntry
*expression
;
987 GtkWidget
*old_focus
;
990 SheetWidgetButton
*swb
;
995 cb_button_set_focus (G_GNUC_UNUSED GtkWidget
*window
, GtkWidget
*focus_widget
,
996 ButtonConfigState
*state
)
998 /* Note: half of the set-focus action is handle by the default
999 * callback installed by wbc_gtk_attach_guru */
1001 /* Force an update of the content in case it needs tweaking (eg make it
1003 if (state
->old_focus
!= NULL
&&
1004 GNM_EXPR_ENTRY_IS (gtk_widget_get_parent (state
->old_focus
))) {
1006 GnmExprTop
const *texpr
= gnm_expr_entry_parse
1007 (GNM_EXPR_ENTRY (gtk_widget_get_parent (state
->old_focus
)),
1008 parse_pos_init_sheet (&pp
, state
->sheet
),
1009 NULL
, FALSE
, GNM_EXPR_PARSE_DEFAULT
);
1011 gnm_expr_top_unref (texpr
);
1013 state
->old_focus
= focus_widget
;
1017 cb_button_config_destroy (ButtonConfigState
*state
)
1019 g_return_if_fail (state
!= NULL
);
1021 g_free (state
->old_label
);
1022 state
->old_label
= NULL
;
1023 state
->dialog
= NULL
;
1028 cb_button_config_ok_clicked (G_GNUC_UNUSED GtkWidget
*button
, ButtonConfigState
*state
)
1030 SheetObject
*so
= GNM_SO (state
->swb
);
1032 GnmExprTop
const *texpr
= gnm_expr_entry_parse (state
->expression
,
1033 parse_pos_init_sheet (&pp
, so
->sheet
),
1034 NULL
, FALSE
, GNM_EXPR_PARSE_DEFAULT
);
1035 gchar
const *text
= gtk_entry_get_text(GTK_ENTRY(state
->label
));
1037 cmd_so_set_button (GNM_WBC (state
->wbcg
), so
,
1038 texpr
, g_strdup (state
->old_label
), g_strdup (text
));
1040 gtk_widget_destroy (state
->dialog
);
1044 cb_button_config_cancel_clicked (G_GNUC_UNUSED GtkWidget
*button
, ButtonConfigState
*state
)
1046 sheet_widget_button_set_label (GNM_SO (state
->swb
),
1048 gtk_widget_destroy (state
->dialog
);
1052 cb_button_label_changed (GtkEntry
*entry
, ButtonConfigState
*state
)
1054 sheet_widget_button_set_label (GNM_SO (state
->swb
),
1055 gtk_entry_get_text (entry
));
1059 sheet_widget_button_user_config (SheetObject
*so
, SheetControl
*sc
)
1061 SheetWidgetButton
*swb
= GNM_SOW_BUTTON (so
);
1062 WBCGtk
*wbcg
= scg_wbcg (GNM_SCG (sc
));
1063 ButtonConfigState
*state
;
1067 g_return_if_fail (swb
!= NULL
);
1069 /* Only pop up one copy per workbook */
1070 if (gnm_dialog_raise_if_exists (wbcg
, SHEET_OBJECT_CONFIG_KEY
))
1073 gui
= gnm_gtk_builder_load ("res:ui/so-button.ui", NULL
, GO_CMD_CONTEXT (wbcg
));
1076 state
= g_new (ButtonConfigState
, 1);
1079 state
->sheet
= sc_sheet (sc
);
1080 state
->old_focus
= NULL
;
1081 state
->old_label
= g_strdup (swb
->label
);
1082 state
->dialog
= go_gtk_builder_get_widget (gui
, "SO-Button");
1084 grid
= go_gtk_builder_get_widget (gui
, "main-grid");
1086 state
->expression
= gnm_expr_entry_new (wbcg
, TRUE
);
1087 gnm_expr_entry_set_flags (state
->expression
,
1088 GNM_EE_FORCE_ABS_REF
| GNM_EE_SHEET_OPTIONAL
| GNM_EE_SINGLE_RANGE
,
1090 gnm_expr_entry_load_from_dep (state
->expression
, &swb
->dep
);
1091 go_atk_setup_label (go_gtk_builder_get_widget (gui
, "label_linkto"),
1092 GTK_WIDGET (state
->expression
));
1093 gtk_grid_attach (GTK_GRID (grid
),
1094 GTK_WIDGET (state
->expression
), 1, 0, 1, 1);
1095 gtk_widget_show (GTK_WIDGET (state
->expression
));
1097 state
->label
= go_gtk_builder_get_widget (gui
, "label_entry");
1098 gtk_entry_set_text (GTK_ENTRY (state
->label
), swb
->label
);
1099 gtk_editable_select_region (GTK_EDITABLE(state
->label
), 0, -1);
1100 gnm_editable_enters (GTK_WINDOW (state
->dialog
),
1101 GTK_WIDGET (state
->expression
));
1102 gnm_editable_enters (GTK_WINDOW (state
->dialog
),
1103 GTK_WIDGET (state
->label
));
1105 g_signal_connect (G_OBJECT (state
->label
),
1107 G_CALLBACK (cb_button_label_changed
), state
);
1108 g_signal_connect (G_OBJECT (go_gtk_builder_get_widget (gui
, "ok_button")),
1110 G_CALLBACK (cb_button_config_ok_clicked
), state
);
1111 g_signal_connect (G_OBJECT (go_gtk_builder_get_widget (gui
, "cancel_button")),
1113 G_CALLBACK (cb_button_config_cancel_clicked
), state
);
1115 gnm_init_help_button (
1116 go_gtk_builder_get_widget (gui
, "help_button"),
1117 GNUMERIC_HELP_LINK_SO_BUTTON
);
1119 gnm_keyed_dialog (state
->wbcg
, GTK_WINDOW (state
->dialog
),
1120 SHEET_OBJECT_CONFIG_KEY
);
1122 wbc_gtk_attach_guru (state
->wbcg
, state
->dialog
);
1123 g_object_set_data_full (G_OBJECT (state
->dialog
),
1124 "state", state
, (GDestroyNotify
) cb_button_config_destroy
);
1126 /* Note: half of the set-focus action is handle by the default */
1127 /* callback installed by wbc_gtk_attach_guru */
1128 g_signal_connect (G_OBJECT (state
->dialog
), "set-focus",
1129 G_CALLBACK (cb_button_set_focus
), state
);
1130 g_object_unref (gui
);
1132 gtk_widget_show (state
->dialog
);
1136 sheet_widget_button_set_sheet (SheetObject
*so
, Sheet
*sheet
)
1138 SheetWidgetButton
*swb
= GNM_SOW_BUTTON (so
);
1140 dependent_set_sheet (&swb
->dep
, sheet
);
1146 sheet_widget_button_foreach_dep (SheetObject
*so
,
1147 SheetObjectForeachDepFunc func
,
1150 SheetWidgetButton
*swb
= GNM_SOW_BUTTON (so
);
1151 func (&swb
->dep
, so
, user
);
1155 sheet_widget_button_write_xml_sax (SheetObject
const *so
, GsfXMLOut
*output
,
1156 GnmConventions
const *convs
)
1159 SheetWidgetButton
*swb
= GNM_SOW_BUTTON (so
);
1160 gsf_xml_out_add_cstr (output
, "Label", swb
->label
);
1161 gsf_xml_out_add_int (output
, "Value", swb
->value
);
1162 sax_write_dep (output
, &swb
->dep
, "Input", convs
);
1166 sheet_widget_button_prep_sax_parser (SheetObject
*so
, GsfXMLIn
*xin
,
1167 xmlChar
const **attrs
,
1168 GnmConventions
const *convs
)
1170 SheetWidgetButton
*swb
= GNM_SOW_BUTTON (so
);
1171 for (; attrs
!= NULL
&& attrs
[0] && attrs
[1] ; attrs
+= 2)
1172 if (attr_eq (attrs
[0], "Label"))
1173 g_object_set (G_OBJECT (swb
), "text", attrs
[1], NULL
);
1174 else if (gnm_xml_attr_int (attrs
, "Value", &swb
->value
))
1176 else if (sax_read_dep (attrs
, "Input", &swb
->dep
, xin
, convs
))
1181 sheet_widget_button_set_link (SheetObject
*so
, GnmExprTop
const *texpr
)
1183 SheetWidgetButton
*swb
= GNM_SOW_BUTTON (so
);
1184 dependent_set_expr (&swb
->dep
, texpr
);
1185 if (texpr
&& swb
->dep
.sheet
)
1186 dependent_link (&swb
->dep
);
1190 sheet_widget_button_get_link (SheetObject
*so
)
1192 SheetWidgetButton
*swb
= GNM_SOW_BUTTON (so
);
1193 GnmExprTop
const *texpr
= swb
->dep
.texpr
;
1196 gnm_expr_top_ref (texpr
);
1203 sheet_widget_button_set_label (SheetObject
*so
, char const *str
)
1206 SheetWidgetButton
*swb
= GNM_SOW_BUTTON (so
);
1209 if (go_str_compare (str
, swb
->label
) == 0)
1212 new_label
= g_strdup (str
);
1213 g_free (swb
->label
);
1214 swb
->label
= new_label
;
1216 for (ptr
= swb
->sow
.so
.realized_list
; ptr
!= NULL
; ptr
= ptr
->next
) {
1217 SheetObjectView
*view
= ptr
->data
;
1218 GocWidget
*item
= get_goc_widget (view
);
1219 gtk_button_set_label (GTK_BUTTON (item
->widget
), swb
->label
);
1224 sheet_widget_button_set_markup (SheetObject
*so
, PangoAttrList
*markup
)
1227 SheetWidgetButton
*swb
= GNM_SOW_BUTTON (so
);
1229 if (markup
== swb
->markup
)
1232 if (swb
->markup
) pango_attr_list_unref (swb
->markup
);
1233 swb
->markup
= markup
;
1234 if (markup
) pango_attr_list_ref (markup
);
1236 for (ptr
= swb
->sow
.so
.realized_list
; ptr
!= NULL
; ptr
= ptr
->next
) {
1237 SheetObjectView
*view
= ptr
->data
;
1238 GocWidget
*item
= get_goc_widget (view
);
1240 GTK_LABEL (gtk_bin_get_child (GTK_BIN (item
->widget
)));
1241 gtk_label_set_attributes (lab
, swb
->markup
);
1246 sheet_widget_button_draw_cairo (SheetObject
const *so
, cairo_t
*cr
,
1247 double width
, double height
)
1249 SheetWidgetButton
*swb
= GNM_SOW_BUTTON (so
);
1250 int twidth
, theight
;
1254 if (height
< 3 * radius
)
1255 radius
= height
/ 3.;
1256 if (width
< 3 * radius
)
1257 radius
= width
/ 3.;
1260 half_line
= radius
* 0.15;
1263 cairo_set_line_width (cr
, 2 * half_line
);
1264 cairo_set_source_rgb(cr
, 0.5, 0.5, 0.5);
1266 cairo_new_path (cr
);
1267 cairo_arc (cr
, radius
+ half_line
, radius
+ half_line
, radius
, M_PI
, - M_PI
/2);
1268 cairo_arc (cr
, width
- (radius
+ half_line
), radius
+ half_line
,
1269 radius
, - M_PI
/2, 0);
1270 cairo_arc (cr
, width
- (radius
+ half_line
), height
- (radius
+ half_line
),
1272 cairo_arc (cr
, (radius
+ half_line
), height
- (radius
+ half_line
),
1273 radius
, M_PI
/2, M_PI
);
1274 cairo_close_path (cr
);
1277 cairo_set_source_rgb(cr
, 0, 0, 0);
1279 cairo_move_to (cr
, width
/2., height
/2.);
1281 twidth
= 0.8 * width
;
1282 theight
= 0.8 * height
;
1283 draw_cairo_text (cr
, swb
->label
, &twidth
, &theight
, TRUE
, TRUE
, TRUE
, 0, TRUE
);
1285 cairo_new_path (cr
);
1289 SOW_MAKE_TYPE (button
, Button
,
1290 sheet_widget_button_user_config
,
1291 sheet_widget_button_set_sheet
,
1293 sheet_widget_button_foreach_dep
,
1294 sheet_widget_button_copy
,
1295 sheet_widget_button_write_xml_sax
,
1296 sheet_widget_button_prep_sax_parser
,
1297 sheet_widget_button_get_property
,
1298 sheet_widget_button_set_property
,
1299 sheet_widget_button_draw_cairo
,
1301 g_object_class_install_property
1302 (object_class
, SOB_PROP_TEXT
,
1303 g_param_spec_string ("text", NULL
, NULL
, NULL
,
1304 GSF_PARAM_STATIC
| G_PARAM_READWRITE
));
1305 g_object_class_install_property
1306 (object_class
, SOB_PROP_MARKUP
,
1307 g_param_spec_boxed ("markup", NULL
, NULL
, PANGO_TYPE_ATTR_LIST
,
1308 GSF_PARAM_STATIC
| G_PARAM_READWRITE
));
1311 /****************************************************************************/
1313 #define DEP_TO_ADJUSTMENT(d_ptr) (SheetWidgetAdjustment *)(((char *)d_ptr) - G_STRUCT_OFFSET(SheetWidgetAdjustment, dep))
1314 #define GNM_SOW_ADJUSTMENT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GNM_SOW_ADJUSTMENT_TYPE, SheetWidgetAdjustmentClass))
1315 #define SWA_CLASS(so) (GNM_SOW_ADJUSTMENT_CLASS (G_OBJECT_GET_CLASS(so)))
1318 SheetObjectWidget sow
;
1320 gboolean being_updated
;
1322 GtkAdjustment
*adjustment
;
1324 gboolean horizontal
;
1325 } SheetWidgetAdjustment
;
1328 SheetObjectWidgetClass parent_class
;
1330 gboolean has_orientation
;
1331 } SheetWidgetAdjustmentClass
;
1338 #ifndef g_signal_handlers_disconnect_by_data
1339 #define g_signal_handlers_disconnect_by_data(instance, data) \
1340 g_signal_handlers_disconnect_matched ((instance), G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, (data))
1343 cb_range_destroyed (GtkWidget
*w
, SheetWidgetAdjustment
*swa
)
1345 GObject
*accessible
= G_OBJECT (gtk_widget_get_accessible (w
));
1347 g_signal_handlers_disconnect_by_data (swa
->adjustment
, accessible
);
1351 sheet_widget_adjustment_set_value (SheetWidgetAdjustment
*swa
, double new_val
)
1353 if (swa
->being_updated
)
1355 swa
->being_updated
= TRUE
;
1356 gtk_adjustment_set_value (swa
->adjustment
, new_val
);
1357 swa
->being_updated
= FALSE
;
1361 * sheet_widget_adjustment_get_adjustment:
1364 * Returns: (transfer none): the associated #GtkAdjustment.
1367 sheet_widget_adjustment_get_adjustment (SheetObject
*so
)
1369 g_return_val_if_fail (GNM_IS_SOW_ADJUSTMENT (so
), NULL
);
1370 return (GNM_SOW_ADJUSTMENT (so
)->adjustment
);
1374 sheet_widget_adjustment_get_horizontal (SheetObject
*so
)
1376 g_return_val_if_fail (GNM_IS_SOW_ADJUSTMENT (so
), TRUE
);
1377 return (GNM_SOW_ADJUSTMENT (so
)->horizontal
);
1381 sheet_widget_adjustment_set_link (SheetObject
*so
, GnmExprTop
const *texpr
)
1383 SheetWidgetAdjustment
*swa
= GNM_SOW_ADJUSTMENT (so
);
1384 dependent_set_expr (&swa
->dep
, texpr
);
1385 if (texpr
&& swa
->dep
.sheet
)
1386 dependent_link (&swa
->dep
);
1390 sheet_widget_adjustment_get_link (SheetObject
*so
)
1392 SheetWidgetAdjustment
*swa
= GNM_SOW_ADJUSTMENT (so
);
1393 GnmExprTop
const *texpr
= swa
->dep
.texpr
;
1396 gnm_expr_top_ref (texpr
);
1403 adjustment_eval (GnmDependent
*dep
)
1408 v
= gnm_expr_top_eval (dep
->texpr
, eval_pos_init_dep (&pos
, dep
),
1409 GNM_EXPR_EVAL_SCALAR_NON_EMPTY
);
1410 sheet_widget_adjustment_set_value (DEP_TO_ADJUSTMENT(dep
),
1411 value_get_as_float (v
));
1416 adjustment_debug_name (GnmDependent
const *dep
, GString
*target
)
1418 g_string_append_printf (target
, "Adjustment%p", (void *)dep
);
1421 static DEPENDENT_MAKE_TYPE (adjustment
, NULL
)
1424 cb_adjustment_widget_value_changed (GtkWidget
*widget
,
1425 SheetWidgetAdjustment
*swa
)
1429 if (swa
->being_updated
)
1432 if (so_get_ref (GNM_SO (swa
), &ref
, TRUE
) != NULL
) {
1433 GnmCell
*cell
= sheet_cell_fetch (ref
.sheet
, ref
.col
, ref
.row
);
1434 /* TODO : add more control for precision, XL is stupid */
1435 int new_val
= gnm_fake_round (gtk_adjustment_get_value (swa
->adjustment
));
1436 if (cell
->value
!= NULL
&&
1437 VALUE_IS_FLOAT (cell
->value
) &&
1438 value_get_as_float (cell
->value
) == new_val
)
1441 swa
->being_updated
= TRUE
;
1442 cmd_so_set_value (widget_wbc (widget
),
1443 /* FIXME: This text sucks: */
1445 &ref
, value_new_int (new_val
),
1446 sheet_object_get_sheet (GNM_SO (swa
)));
1447 swa
->being_updated
= FALSE
;
1452 sheet_widget_adjustment_set_horizontal (SheetObject
*so
,
1453 gboolean horizontal
)
1455 SheetWidgetAdjustment
*swa
= (SheetWidgetAdjustment
*)so
;
1459 if (!SWA_CLASS (swa
)->has_orientation
)
1461 horizontal
= !!horizontal
;
1462 if (horizontal
== swa
->horizontal
)
1464 swa
->horizontal
= horizontal
;
1465 o
= horizontal
? GTK_ORIENTATION_HORIZONTAL
: GTK_ORIENTATION_VERTICAL
;
1467 /* Change direction for all realized widgets. */
1468 for (ptr
= swa
->sow
.so
.realized_list
; ptr
!= NULL
; ptr
= ptr
->next
) {
1469 SheetObjectView
*view
= ptr
->data
;
1470 GocWidget
*item
= get_goc_widget (view
);
1471 gtk_orientable_set_orientation (GTK_ORIENTABLE (item
->widget
), o
);
1477 sheet_widget_adjustment_get_property (GObject
*obj
, guint param_id
,
1478 GValue
*value
, GParamSpec
*pspec
)
1480 SheetWidgetAdjustment
*swa
= GNM_SOW_ADJUSTMENT (obj
);
1483 case SWA_PROP_HORIZONTAL
:
1484 g_value_set_boolean (value
, swa
->horizontal
);
1487 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj
, param_id
, pspec
);
1493 sheet_widget_adjustment_set_property (GObject
*obj
, guint param_id
,
1494 GValue
const *value
, GParamSpec
*pspec
)
1496 SheetWidgetAdjustment
*swa
= GNM_SOW_ADJUSTMENT (obj
);
1499 case SWA_PROP_HORIZONTAL
:
1500 sheet_widget_adjustment_set_horizontal (GNM_SO (swa
), g_value_get_boolean (value
));
1503 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj
, param_id
, pspec
);
1509 sheet_widget_adjustment_init_full (SheetWidgetAdjustment
*swa
,
1510 GnmCellRef
const *ref
,
1511 gboolean horizontal
)
1514 g_return_if_fail (swa
!= NULL
);
1517 so
->flags
&= ~SHEET_OBJECT_PRINT
;
1519 swa
->adjustment
= GTK_ADJUSTMENT (gtk_adjustment_new (0., 0., 100., 1., 10., 0.));
1520 g_object_ref_sink (swa
->adjustment
);
1522 swa
->horizontal
= horizontal
;
1523 swa
->being_updated
= FALSE
;
1524 swa
->dep
.sheet
= NULL
;
1525 swa
->dep
.flags
= adjustment_get_dep_type ();
1526 swa
->dep
.texpr
= (ref
!= NULL
)
1527 ? gnm_expr_top_new (gnm_expr_new_cellref (ref
))
1532 sheet_widget_adjustment_init (SheetWidgetAdjustment
*swa
)
1534 sheet_widget_adjustment_init_full (swa
, NULL
, FALSE
);
1538 sheet_widget_adjustment_finalize (GObject
*obj
)
1540 SheetWidgetAdjustment
*swa
= GNM_SOW_ADJUSTMENT (obj
);
1542 g_return_if_fail (swa
!= NULL
);
1544 dependent_set_expr (&swa
->dep
, NULL
);
1545 if (swa
->adjustment
!= NULL
) {
1546 g_object_unref (swa
->adjustment
);
1547 swa
->adjustment
= NULL
;
1550 sheet_object_widget_class
->finalize (obj
);
1554 sheet_widget_adjustment_copy (SheetObject
*dst
, SheetObject
const *src
)
1556 SheetWidgetAdjustment
const *src_swa
= GNM_SOW_ADJUSTMENT (src
);
1557 SheetWidgetAdjustment
*dst_swa
= GNM_SOW_ADJUSTMENT (dst
);
1558 GtkAdjustment
*dst_adjust
, *src_adjust
;
1561 sheet_widget_adjustment_init_full (dst_swa
,
1562 so_get_ref (src
, &ref
, FALSE
),
1563 src_swa
->horizontal
);
1564 dst_adjust
= dst_swa
->adjustment
;
1565 src_adjust
= src_swa
->adjustment
;
1567 gtk_adjustment_configure
1569 gtk_adjustment_get_value (src_adjust
),
1570 gtk_adjustment_get_lower (src_adjust
),
1571 gtk_adjustment_get_upper (src_adjust
),
1572 gtk_adjustment_get_step_increment (src_adjust
),
1573 gtk_adjustment_get_page_increment (src_adjust
),
1574 gtk_adjustment_get_page_size (src_adjust
));
1579 GnmExprEntry
*expression
;
1584 GtkWidget
*direction_h
;
1585 GtkWidget
*direction_v
;
1588 GtkWidget
*old_focus
;
1591 SheetWidgetAdjustment
*swa
;
1593 } AdjustmentConfigState
;
1596 cb_adjustment_set_focus (G_GNUC_UNUSED GtkWidget
*window
, GtkWidget
*focus_widget
,
1597 AdjustmentConfigState
*state
)
1601 /* Note: half of the set-focus action is handle by the default
1602 * callback installed by wbc_gtk_attach_guru. */
1604 ofp
= state
->old_focus
1605 ? gtk_widget_get_parent (state
->old_focus
)
1607 /* Force an update of the content in case it needs tweaking (eg make it
1609 if (ofp
&& GNM_EXPR_ENTRY_IS (ofp
)) {
1611 GnmExprTop
const *texpr
= gnm_expr_entry_parse (
1612 GNM_EXPR_ENTRY (ofp
),
1613 parse_pos_init_sheet (&pp
, state
->sheet
),
1614 NULL
, FALSE
, GNM_EXPR_PARSE_DEFAULT
);
1616 gnm_expr_top_unref (texpr
);
1618 state
->old_focus
= focus_widget
;
1622 cb_adjustment_config_destroy (AdjustmentConfigState
*state
)
1624 g_return_if_fail (state
!= NULL
);
1626 g_free (state
->undo_label
);
1628 state
->dialog
= NULL
;
1633 cb_adjustment_config_ok_clicked (G_GNUC_UNUSED GtkWidget
*button
, AdjustmentConfigState
*state
)
1635 SheetObject
*so
= GNM_SO (state
->swa
);
1637 GnmExprTop
const *texpr
= gnm_expr_entry_parse (state
->expression
,
1638 parse_pos_init_sheet (&pp
, so
->sheet
),
1639 NULL
, FALSE
, GNM_EXPR_PARSE_DEFAULT
);
1640 gboolean horizontal
;
1642 horizontal
= state
->direction_h
1643 ? gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (state
->direction_h
))
1644 : state
->swa
->horizontal
;
1646 cmd_so_set_adjustment (GNM_WBC (state
->wbcg
), so
,
1649 gtk_spin_button_get_value_as_int (
1650 GTK_SPIN_BUTTON (state
->min
)),
1651 gtk_spin_button_get_value_as_int (
1652 GTK_SPIN_BUTTON (state
->max
)),
1653 gtk_spin_button_get_value_as_int (
1654 GTK_SPIN_BUTTON (state
->inc
)),
1655 gtk_spin_button_get_value_as_int (
1656 GTK_SPIN_BUTTON (state
->page
)),
1659 gtk_widget_destroy (state
->dialog
);
1663 cb_adjustment_config_cancel_clicked (G_GNUC_UNUSED GtkWidget
*button
, AdjustmentConfigState
*state
)
1665 gtk_widget_destroy (state
->dialog
);
1669 sheet_widget_adjustment_user_config_impl (SheetObject
*so
, SheetControl
*sc
, char const *undo_label
, char const *dialog_label
)
1671 SheetWidgetAdjustment
*swa
= GNM_SOW_ADJUSTMENT (so
);
1672 SheetWidgetAdjustmentClass
*swa_class
= SWA_CLASS (swa
);
1673 WBCGtk
*wbcg
= scg_wbcg (GNM_SCG (sc
));
1674 AdjustmentConfigState
*state
;
1677 gboolean has_directions
= swa_class
->has_orientation
;
1679 /* Only pop up one copy per workbook */
1680 if (gnm_dialog_raise_if_exists (wbcg
, SHEET_OBJECT_CONFIG_KEY
))
1683 gui
= gnm_gtk_builder_load ("res:ui/so-scrollbar.ui", NULL
, GO_CMD_CONTEXT (wbcg
));
1686 state
= g_new (AdjustmentConfigState
, 1);
1689 state
->sheet
= sc_sheet (sc
);
1690 state
->old_focus
= NULL
;
1691 state
->undo_label
= (undo_label
== NULL
) ? NULL
: g_strdup (undo_label
);
1692 state
->dialog
= go_gtk_builder_get_widget (gui
, "SO-Scrollbar");
1694 if (dialog_label
!= NULL
)
1695 gtk_window_set_title (GTK_WINDOW (state
->dialog
), dialog_label
);
1697 grid
= go_gtk_builder_get_widget (gui
, "main-grid");
1699 state
->expression
= gnm_expr_entry_new (wbcg
, TRUE
);
1700 gnm_expr_entry_set_flags (state
->expression
,
1701 GNM_EE_FORCE_ABS_REF
| GNM_EE_SHEET_OPTIONAL
| GNM_EE_SINGLE_RANGE
,
1703 gnm_expr_entry_load_from_dep (state
->expression
, &swa
->dep
);
1704 go_atk_setup_label (go_gtk_builder_get_widget (gui
, "label_linkto"),
1705 GTK_WIDGET (state
->expression
));
1706 gtk_grid_attach (GTK_GRID (grid
),
1707 GTK_WIDGET (state
->expression
), 1, 0, 2, 1);
1708 gtk_widget_show (GTK_WIDGET (state
->expression
));
1710 if (has_directions
) {
1711 state
->direction_h
= go_gtk_builder_get_widget (gui
, "direction_h");
1712 state
->direction_v
= go_gtk_builder_get_widget (gui
, "direction_v");
1713 gtk_toggle_button_set_active
1714 (GTK_TOGGLE_BUTTON (swa
->horizontal
1715 ? state
->direction_h
1716 : state
->direction_v
),
1719 state
->direction_h
= NULL
;
1720 state
->direction_v
= NULL
;
1721 gtk_widget_destroy (go_gtk_builder_get_widget (gui
, "direction_label"));
1722 gtk_widget_destroy (go_gtk_builder_get_widget (gui
, "direction_h"));
1723 gtk_widget_destroy (go_gtk_builder_get_widget (gui
, "direction_v"));
1726 /* TODO : This is silly, no need to be similar to XL here. */
1727 state
->min
= go_gtk_builder_get_widget (gui
, "spin_min");
1728 gtk_spin_button_set_value (GTK_SPIN_BUTTON (state
->min
),
1729 gtk_adjustment_get_lower (swa
->adjustment
));
1730 state
->max
= go_gtk_builder_get_widget (gui
, "spin_max");
1731 gtk_spin_button_set_value (GTK_SPIN_BUTTON (state
->max
),
1732 gtk_adjustment_get_upper (swa
->adjustment
));
1733 state
->inc
= go_gtk_builder_get_widget (gui
, "spin_increment");
1734 gtk_spin_button_set_value (GTK_SPIN_BUTTON (state
->inc
),
1735 gtk_adjustment_get_step_increment (swa
->adjustment
));
1736 state
->page
= go_gtk_builder_get_widget (gui
, "spin_page");
1737 gtk_spin_button_set_value (GTK_SPIN_BUTTON (state
->page
),
1738 gtk_adjustment_get_page_increment (swa
->adjustment
));
1740 gnm_editable_enters (GTK_WINDOW (state
->dialog
),
1741 GTK_WIDGET (state
->expression
));
1742 gnm_editable_enters (GTK_WINDOW (state
->dialog
),
1743 GTK_WIDGET (state
->min
));
1744 gnm_editable_enters (GTK_WINDOW (state
->dialog
),
1745 GTK_WIDGET (state
->max
));
1746 gnm_editable_enters (GTK_WINDOW (state
->dialog
),
1747 GTK_WIDGET (state
->inc
));
1748 gnm_editable_enters (GTK_WINDOW (state
->dialog
),
1749 GTK_WIDGET (state
->page
));
1750 g_signal_connect (G_OBJECT (go_gtk_builder_get_widget (gui
, "ok_button")),
1752 G_CALLBACK (cb_adjustment_config_ok_clicked
), state
);
1753 g_signal_connect (G_OBJECT (go_gtk_builder_get_widget (gui
, "cancel_button")),
1755 G_CALLBACK (cb_adjustment_config_cancel_clicked
), state
);
1757 gnm_init_help_button (
1758 go_gtk_builder_get_widget (gui
, "help_button"),
1759 GNUMERIC_HELP_LINK_SO_ADJUSTMENT
);
1761 gnm_keyed_dialog (state
->wbcg
, GTK_WINDOW (state
->dialog
),
1762 SHEET_OBJECT_CONFIG_KEY
);
1764 wbc_gtk_attach_guru (state
->wbcg
, state
->dialog
);
1765 g_object_set_data_full (G_OBJECT (state
->dialog
),
1766 "state", state
, (GDestroyNotify
) cb_adjustment_config_destroy
);
1768 /* Note: half of the set-focus action is handle by the default */
1769 /* callback installed by wbc_gtk_attach_guru */
1770 g_signal_connect (G_OBJECT (state
->dialog
), "set-focus",
1771 G_CALLBACK (cb_adjustment_set_focus
), state
);
1772 g_object_unref (gui
);
1774 gtk_widget_show (state
->dialog
);
1778 sheet_widget_adjustment_user_config (SheetObject
*so
, SheetControl
*sc
)
1780 sheet_widget_adjustment_user_config_impl (so
, sc
, N_("Configure Adjustment"),
1781 N_("Adjustment Properties"));
1785 sheet_widget_adjustment_set_sheet (SheetObject
*so
, Sheet
*sheet
)
1787 SheetWidgetAdjustment
*swa
= GNM_SOW_ADJUSTMENT (so
);
1789 dependent_set_sheet (&swa
->dep
, sheet
);
1795 sheet_widget_adjustment_foreach_dep (SheetObject
*so
,
1796 SheetObjectForeachDepFunc func
,
1799 SheetWidgetAdjustment
*swa
= GNM_SOW_ADJUSTMENT (so
);
1800 func (&swa
->dep
, so
, user
);
1804 sheet_widget_adjustment_write_xml_sax (SheetObject
const *so
, GsfXMLOut
*output
,
1805 GnmConventions
const *convs
)
1807 SheetWidgetAdjustment
const *swa
= GNM_SOW_ADJUSTMENT (so
);
1808 SheetWidgetAdjustmentClass
*swa_class
= SWA_CLASS (so
);
1810 go_xml_out_add_double (output
, "Min", gtk_adjustment_get_lower (swa
->adjustment
));
1811 go_xml_out_add_double (output
, "Max", gtk_adjustment_get_upper (swa
->adjustment
));
1812 go_xml_out_add_double (output
, "Inc", gtk_adjustment_get_step_increment (swa
->adjustment
));
1813 go_xml_out_add_double (output
, "Page", gtk_adjustment_get_page_increment (swa
->adjustment
));
1814 go_xml_out_add_double (output
, "Value", gtk_adjustment_get_value (swa
->adjustment
));
1816 if (swa_class
->has_orientation
)
1817 gsf_xml_out_add_bool (output
, "Horizontal", swa
->horizontal
);
1819 sax_write_dep (output
, &swa
->dep
, "Input", convs
);
1823 sheet_widget_adjustment_prep_sax_parser (SheetObject
*so
, GsfXMLIn
*xin
,
1824 xmlChar
const **attrs
,
1825 GnmConventions
const *convs
)
1827 SheetWidgetAdjustment
*swa
= GNM_SOW_ADJUSTMENT (so
);
1828 SheetWidgetAdjustmentClass
*swa_class
= SWA_CLASS (so
);
1829 swa
->horizontal
= FALSE
;
1831 for (; attrs
!= NULL
&& attrs
[0] && attrs
[1] ; attrs
+= 2) {
1835 if (gnm_xml_attr_double (attrs
, "Min", &tmp
))
1836 gtk_adjustment_set_lower (swa
->adjustment
, tmp
);
1837 else if (gnm_xml_attr_double (attrs
, "Max", &tmp
))
1838 gtk_adjustment_set_upper (swa
->adjustment
, tmp
); /* allow scrolling to max */
1839 else if (gnm_xml_attr_double (attrs
, "Inc", &tmp
))
1840 gtk_adjustment_set_step_increment (swa
->adjustment
, tmp
);
1841 else if (gnm_xml_attr_double (attrs
, "Page", &tmp
))
1842 gtk_adjustment_set_page_increment (swa
->adjustment
, tmp
);
1843 else if (gnm_xml_attr_double (attrs
, "Value", &tmp
))
1844 gtk_adjustment_set_value (swa
->adjustment
, tmp
);
1845 else if (sax_read_dep (attrs
, "Input", &swa
->dep
, xin
, convs
))
1847 else if (swa_class
->has_orientation
&&
1848 gnm_xml_attr_bool (attrs
, "Horizontal", &b
))
1849 swa
->horizontal
= b
;
1852 swa
->dep
.flags
= adjustment_get_dep_type ();
1856 sheet_widget_adjustment_set_details (SheetObject
*so
, GnmExprTop
const *tlink
,
1857 int value
, int min
, int max
,
1860 SheetWidgetAdjustment
*swa
= GNM_SOW_ADJUSTMENT (so
);
1863 g_return_if_fail (swa
!= NULL
);
1865 dependent_set_expr (&swa
->dep
, tlink
);
1866 if (tlink
&& swa
->dep
.sheet
)
1867 dependent_link (&swa
->dep
);
1869 page_size
= gtk_adjustment_get_page_size (swa
->adjustment
); /* ??? */
1870 gtk_adjustment_configure (swa
->adjustment
,
1871 value
, min
, max
, inc
, page
, page_size
);
1875 sheet_widget_adjustment_create_widget (G_GNUC_UNUSED SheetObjectWidget
*sow
)
1877 g_assert_not_reached ();
1881 SOW_MAKE_TYPE (adjustment
, Adjustment
,
1882 sheet_widget_adjustment_user_config
,
1883 sheet_widget_adjustment_set_sheet
,
1885 sheet_widget_adjustment_foreach_dep
,
1886 sheet_widget_adjustment_copy
,
1887 sheet_widget_adjustment_write_xml_sax
,
1888 sheet_widget_adjustment_prep_sax_parser
,
1889 sheet_widget_adjustment_get_property
,
1890 sheet_widget_adjustment_set_property
,
1891 sheet_widget_draw_cairo
,
1893 ((SheetWidgetAdjustmentClass
*) object_class
)->has_orientation
= TRUE
;
1894 g_object_class_install_property
1895 (object_class
, SWA_PROP_HORIZONTAL
,
1896 g_param_spec_boolean ("horizontal", NULL
, NULL
,
1898 GSF_PARAM_STATIC
| G_PARAM_READWRITE
));
1901 /****************************************************************************/
1903 #define GNM_SOW_SCROLLBAR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNM_SOW_SCROLLBAR_TYPE, SheetWidgetScrollbar))
1904 #define DEP_TO_SCROLLBAR(d_ptr) (SheetWidgetScrollbar *)(((char *)d_ptr) - G_STRUCT_OFFSET(SheetWidgetScrollbar, dep))
1906 typedef SheetWidgetAdjustment SheetWidgetScrollbar
;
1907 typedef SheetWidgetAdjustmentClass SheetWidgetScrollbarClass
;
1910 sheet_widget_scrollbar_create_widget (SheetObjectWidget
*sow
)
1912 SheetWidgetAdjustment
*swa
= GNM_SOW_ADJUSTMENT (sow
);
1915 swa
->being_updated
= TRUE
;
1916 bar
= gtk_scrollbar_new (swa
->horizontal
? GTK_ORIENTATION_HORIZONTAL
: GTK_ORIENTATION_VERTICAL
, swa
->adjustment
);
1917 gtk_widget_set_can_focus (bar
, FALSE
);
1918 g_signal_connect (G_OBJECT (bar
),
1920 G_CALLBACK (cb_adjustment_widget_value_changed
), swa
);
1921 g_signal_connect (G_OBJECT (bar
), "destroy",
1922 G_CALLBACK (cb_range_destroyed
), swa
);
1923 swa
->being_updated
= FALSE
;
1929 sheet_widget_scrollbar_user_config (SheetObject
*so
, SheetControl
*sc
)
1931 sheet_widget_adjustment_user_config_impl (so
, sc
, N_("Configure Scrollbar"),
1932 N_("Scrollbar Properties"));
1935 static void sheet_widget_slider_horizontal_draw_cairo
1936 (SheetObject
const *so
, cairo_t
*cr
, double width
, double height
);
1939 sheet_widget_scrollbar_horizontal_draw_cairo (SheetObject
const *so
, cairo_t
*cr
,
1940 double width
, double height
)
1943 cairo_set_source_rgb(cr
, 0.5, 0.5, 0.5);
1945 cairo_new_path (cr
);
1946 cairo_move_to (cr
, 0., height
/2);
1947 cairo_rel_line_to (cr
, 15., 7.5);
1948 cairo_rel_line_to (cr
, 0, -15);
1949 cairo_close_path (cr
);
1952 cairo_new_path (cr
);
1953 cairo_move_to (cr
, width
, height
/2);
1954 cairo_rel_line_to (cr
, -15., 7.5);
1955 cairo_rel_line_to (cr
, 0, -15);
1956 cairo_close_path (cr
);
1959 cairo_new_path (cr
);
1960 cairo_translate (cr
, 15., 0.);
1961 sheet_widget_slider_horizontal_draw_cairo (so
, cr
, width
- 30, height
);
1966 sheet_widget_scrollbar_vertical_draw_cairo (SheetObject
const *so
, cairo_t
*cr
,
1967 double width
, double height
)
1970 cairo_rotate (cr
, M_PI
/2);
1971 cairo_translate (cr
, 0., -width
);
1972 sheet_widget_scrollbar_horizontal_draw_cairo (so
, cr
, height
, width
);
1977 sheet_widget_scrollbar_draw_cairo (SheetObject
const *so
, cairo_t
*cr
,
1978 double width
, double height
)
1980 SheetWidgetAdjustment
*swa
= GNM_SOW_ADJUSTMENT (so
);
1981 if (swa
->horizontal
)
1982 sheet_widget_scrollbar_horizontal_draw_cairo
1983 (so
, cr
, width
, height
);
1985 sheet_widget_scrollbar_vertical_draw_cairo
1986 (so
, cr
, width
, height
);
1990 sheet_widget_scrollbar_class_init (SheetObjectWidgetClass
*sow_class
)
1992 SheetWidgetAdjustmentClass
*swa_class
= (SheetWidgetAdjustmentClass
*)sow_class
;
1993 SheetObjectClass
*so_class
= GNM_SO_CLASS (sow_class
);
1995 sow_class
->create_widget
= &sheet_widget_scrollbar_create_widget
;
1996 so_class
->user_config
= &sheet_widget_scrollbar_user_config
;
1997 so_class
->draw_cairo
= &sheet_widget_scrollbar_draw_cairo
;
1998 swa_class
->type
= GTK_TYPE_SCROLLBAR
;
2001 GSF_CLASS (SheetWidgetScrollbar
, sheet_widget_scrollbar
,
2002 &sheet_widget_scrollbar_class_init
, NULL
,
2003 GNM_SOW_ADJUSTMENT_TYPE
)
2005 /****************************************************************************/
2007 #define GNM_SOW_SPIN_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNM_SOW_SPIN_BUTTON_TYPE, SheetWidgetSpinbutton))
2008 #define DEP_TO_SPINBUTTON(d_ptr) (SheetWidgetSpinbutton *)(((char *)d_ptr) - G_STRUCT_OFFSET(SheetWidgetSpinbutton, dep))
2010 typedef SheetWidgetAdjustment SheetWidgetSpinbutton
;
2011 typedef SheetWidgetAdjustmentClass SheetWidgetSpinbuttonClass
;
2014 sheet_widget_spinbutton_create_widget (SheetObjectWidget
*sow
)
2016 SheetWidgetAdjustment
*swa
= GNM_SOW_ADJUSTMENT (sow
);
2017 GtkWidget
*spinbutton
;
2019 swa
->being_updated
= TRUE
;
2020 spinbutton
= gtk_spin_button_new
2022 gtk_adjustment_get_step_increment (swa
->adjustment
),
2024 gtk_widget_set_can_focus (spinbutton
, FALSE
);
2025 g_signal_connect (G_OBJECT (spinbutton
),
2027 G_CALLBACK (cb_adjustment_widget_value_changed
), swa
);
2028 g_signal_connect (G_OBJECT (spinbutton
), "destroy",
2029 G_CALLBACK (cb_range_destroyed
), swa
);
2030 swa
->being_updated
= FALSE
;
2035 sheet_widget_spinbutton_user_config (SheetObject
*so
, SheetControl
*sc
)
2037 sheet_widget_adjustment_user_config_impl (so
, sc
, N_("Configure Spinbutton"),
2038 N_("Spinbutton Properties"));
2042 sheet_widget_spinbutton_draw_cairo (SheetObject
const *so
, cairo_t
*cr
,
2043 double width
, double height
)
2045 SheetWidgetAdjustment
*swa
= GNM_SOW_ADJUSTMENT (so
);
2046 GtkAdjustment
*adjustment
= swa
->adjustment
;
2047 double value
= gtk_adjustment_get_value (adjustment
);
2048 int ivalue
= (int) value
;
2049 double halfheight
= height
/2;
2053 cairo_set_line_width (cr
, 0.5);
2054 cairo_set_source_rgb(cr
, 0, 0, 0);
2056 cairo_new_path (cr
);
2057 cairo_move_to (cr
, 0, 0);
2058 cairo_line_to (cr
, width
, 0);
2059 cairo_line_to (cr
, width
, height
);
2060 cairo_line_to (cr
, 0, height
);
2061 cairo_close_path (cr
);
2064 cairo_new_path (cr
);
2065 cairo_move_to (cr
, width
- 10, 0);
2066 cairo_rel_line_to (cr
, 0, height
);
2069 cairo_set_source_rgb(cr
, 0.5, 0.5, 0.5);
2071 cairo_new_path (cr
);
2072 cairo_move_to (cr
, width
- 5, 3);
2073 cairo_rel_line_to (cr
, 3, 3);
2074 cairo_rel_line_to (cr
, -6, 0);
2075 cairo_close_path (cr
);
2078 cairo_new_path (cr
);
2079 cairo_move_to (cr
, width
- 5, height
- 3);
2080 cairo_rel_line_to (cr
, 3, -3);
2081 cairo_rel_line_to (cr
, -6, 0);
2082 cairo_close_path (cr
);
2085 str
= g_strdup_printf ("%i", ivalue
);
2086 cairo_set_source_rgb(cr
, 0, 0, 0);
2087 cairo_move_to (cr
, 4., halfheight
);
2088 draw_cairo_text (cr
, str
, NULL
, NULL
, TRUE
, FALSE
, TRUE
, 0, FALSE
);
2091 cairo_new_path (cr
);
2096 sheet_widget_spinbutton_class_init (SheetObjectWidgetClass
*sow_class
)
2098 SheetWidgetAdjustmentClass
*swa_class
= (SheetWidgetAdjustmentClass
*)sow_class
;
2099 SheetObjectClass
*so_class
= GNM_SO_CLASS (sow_class
);
2101 sow_class
->create_widget
= &sheet_widget_spinbutton_create_widget
;
2102 so_class
->user_config
= &sheet_widget_spinbutton_user_config
;
2103 so_class
->draw_cairo
= &sheet_widget_spinbutton_draw_cairo
;
2105 swa_class
->type
= GTK_TYPE_SPIN_BUTTON
;
2106 swa_class
->has_orientation
= FALSE
;
2109 GSF_CLASS (SheetWidgetSpinbutton
, sheet_widget_spinbutton
,
2110 &sheet_widget_spinbutton_class_init
, NULL
,
2111 GNM_SOW_ADJUSTMENT_TYPE
)
2113 /****************************************************************************/
2115 #define GNM_SOW_SLIDER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNM_SOW_SLIDER_TYPE, SheetWidgetSlider))
2116 #define DEP_TO_SLIDER(d_ptr) (SheetWidgetSlider *)(((char *)d_ptr) - G_STRUCT_OFFSET(SheetWidgetSlider, dep))
2118 typedef SheetWidgetAdjustment SheetWidgetSlider
;
2119 typedef SheetWidgetAdjustmentClass SheetWidgetSliderClass
;
2122 sheet_widget_slider_create_widget (SheetObjectWidget
*sow
)
2124 SheetWidgetAdjustment
*swa
= GNM_SOW_ADJUSTMENT (sow
);
2127 swa
->being_updated
= TRUE
;
2128 slider
= gtk_scale_new (swa
->horizontal
? GTK_ORIENTATION_HORIZONTAL
: GTK_ORIENTATION_VERTICAL
, swa
->adjustment
);
2129 gtk_scale_set_draw_value (GTK_SCALE (slider
), FALSE
);
2130 gtk_widget_set_can_focus (slider
, FALSE
);
2131 g_signal_connect (G_OBJECT (slider
),
2133 G_CALLBACK (cb_adjustment_widget_value_changed
), swa
);
2134 g_signal_connect (G_OBJECT (slider
), "destroy",
2135 G_CALLBACK (cb_range_destroyed
), swa
);
2136 swa
->being_updated
= FALSE
;
2142 sheet_widget_slider_user_config (SheetObject
*so
, SheetControl
*sc
)
2144 sheet_widget_adjustment_user_config_impl (so
, sc
, N_("Configure Slider"),
2145 N_("Slider Properties"));
2149 sheet_widget_slider_horizontal_draw_cairo (SheetObject
const *so
, cairo_t
*cr
,
2150 double width
, double height
)
2152 SheetWidgetAdjustment
*swa
= GNM_SOW_ADJUSTMENT (so
);
2153 GtkAdjustment
*adjustment
= swa
->adjustment
;
2154 double value
= gtk_adjustment_get_value (adjustment
);
2155 double upper
= gtk_adjustment_get_upper (adjustment
);
2156 double lower
= gtk_adjustment_get_lower (adjustment
);
2157 double fraction
= (upper
== lower
) ? 0.0 : (value
- lower
)/(upper
- lower
);
2160 cairo_set_line_width (cr
, 5);
2161 cairo_set_source_rgb(cr
, 0.8, 0.8, 0.8);
2162 cairo_set_line_cap (cr
, CAIRO_LINE_CAP_ROUND
);
2164 cairo_new_path (cr
);
2165 cairo_move_to (cr
, 4, height
/2);
2166 cairo_rel_line_to (cr
, width
- 8., 0);
2169 cairo_set_line_width (cr
, 15);
2170 cairo_set_source_rgb(cr
, 0.5, 0.5, 0.5);
2171 cairo_set_line_cap (cr
, CAIRO_LINE_CAP_ROUND
);
2173 cairo_new_path (cr
);
2174 cairo_move_to (cr
, fraction
* (width
- 8. - 1. - 5. - 5. + 2.5 + 2.5)
2175 - 10. + 10. + 4. + 5. - 2.5, height
/2);
2176 cairo_rel_line_to (cr
, 1, 0);
2179 cairo_new_path (cr
);
2184 sheet_widget_slider_vertical_draw_cairo (SheetObject
const *so
, cairo_t
*cr
,
2185 double width
, double height
)
2188 cairo_rotate (cr
, M_PI
/2);
2189 cairo_translate (cr
, 0., -width
);
2190 sheet_widget_slider_horizontal_draw_cairo (so
, cr
, height
, width
);
2195 sheet_widget_slider_draw_cairo (SheetObject
const *so
, cairo_t
*cr
,
2196 double width
, double height
)
2198 SheetWidgetAdjustment
*swa
= GNM_SOW_ADJUSTMENT (so
);
2199 if (swa
->horizontal
)
2200 sheet_widget_slider_horizontal_draw_cairo (so
, cr
, width
, height
);
2202 sheet_widget_slider_vertical_draw_cairo (so
, cr
, width
, height
);
2206 sheet_widget_slider_class_init (SheetObjectWidgetClass
*sow_class
)
2208 SheetWidgetAdjustmentClass
*swa_class
= (SheetWidgetAdjustmentClass
*)sow_class
;
2209 SheetObjectClass
*so_class
= GNM_SO_CLASS (sow_class
);
2211 sow_class
->create_widget
= &sheet_widget_slider_create_widget
;
2212 so_class
->user_config
= &sheet_widget_slider_user_config
;
2213 so_class
->draw_cairo
= &sheet_widget_slider_draw_cairo
;
2215 swa_class
->type
= GTK_TYPE_SCALE
;
2218 GSF_CLASS (SheetWidgetSlider
, sheet_widget_slider
,
2219 &sheet_widget_slider_class_init
, NULL
,
2220 GNM_SOW_ADJUSTMENT_TYPE
)
2222 /****************************************************************************/
2224 #define GNM_SOW_CHECKBOX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNM_SOW_CHECKBOX_TYPE, SheetWidgetCheckbox))
2225 #define DEP_TO_CHECKBOX(d_ptr) (SheetWidgetCheckbox *)(((char *)d_ptr) - G_STRUCT_OFFSET(SheetWidgetCheckbox, dep))
2228 SheetObjectWidget sow
;
2233 gboolean being_updated
;
2234 } SheetWidgetCheckbox
;
2235 typedef SheetObjectWidgetClass SheetWidgetCheckboxClass
;
2245 sheet_widget_checkbox_set_active (SheetWidgetCheckbox
*swc
)
2249 swc
->being_updated
= TRUE
;
2251 for (ptr
= swc
->sow
.so
.realized_list
; ptr
!= NULL
; ptr
= ptr
->next
) {
2252 SheetObjectView
*view
= ptr
->data
;
2253 GocWidget
*item
= get_goc_widget (view
);
2254 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item
->widget
),
2258 g_object_notify (G_OBJECT (swc
), "active");
2260 swc
->being_updated
= FALSE
;
2264 sheet_widget_checkbox_get_property (GObject
*obj
, guint param_id
,
2265 GValue
*value
, GParamSpec
*pspec
)
2267 SheetWidgetCheckbox
*swc
= GNM_SOW_CHECKBOX (obj
);
2270 case SOC_PROP_ACTIVE
:
2271 g_value_set_boolean (value
, swc
->value
);
2274 g_value_set_string (value
, swc
->label
);
2276 case SOC_PROP_MARKUP
:
2277 g_value_set_boxed (value
, NULL
); /* swc->markup */
2280 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj
, param_id
, pspec
);
2286 sheet_widget_checkbox_set_property (GObject
*obj
, guint param_id
,
2287 GValue
const *value
, GParamSpec
*pspec
)
2289 SheetWidgetCheckbox
*swc
= GNM_SOW_CHECKBOX (obj
);
2292 case SOC_PROP_ACTIVE
:
2293 swc
->value
= g_value_get_boolean (value
);
2294 sheet_widget_checkbox_set_active (swc
);
2297 sheet_widget_checkbox_set_label (GNM_SO (swc
),
2298 g_value_get_string (value
));
2300 case SOC_PROP_MARKUP
:
2302 sheet_widget_checkbox_set_markup (GNM_SO (swc
),
2303 g_value_peek_pointer (value
));
2307 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj
, param_id
, pspec
);
2313 checkbox_eval (GnmDependent
*dep
)
2317 gboolean err
, result
;
2319 v
= gnm_expr_top_eval (dep
->texpr
, eval_pos_init_dep (&pos
, dep
),
2320 GNM_EXPR_EVAL_SCALAR_NON_EMPTY
);
2321 result
= value_get_as_bool (v
, &err
);
2324 SheetWidgetCheckbox
*swc
= DEP_TO_CHECKBOX(dep
);
2326 swc
->value
= result
;
2327 sheet_widget_checkbox_set_active (swc
);
2332 checkbox_debug_name (GnmDependent
const *dep
, GString
*target
)
2334 g_string_append_printf (target
, "Checkbox%p", (void *)dep
);
2337 static DEPENDENT_MAKE_TYPE (checkbox
, NULL
)
2340 sheet_widget_checkbox_init_full (SheetWidgetCheckbox
*swc
,
2341 GnmCellRef
const *ref
, char const *label
)
2343 static int counter
= 0;
2345 g_return_if_fail (swc
!= NULL
);
2347 swc
->label
= label
? g_strdup (label
) : g_strdup_printf (_("CheckBox %d"), ++counter
);
2348 swc
->being_updated
= FALSE
;
2350 swc
->dep
.sheet
= NULL
;
2351 swc
->dep
.flags
= checkbox_get_dep_type ();
2352 swc
->dep
.texpr
= (ref
!= NULL
)
2353 ? gnm_expr_top_new (gnm_expr_new_cellref (ref
))
2358 sheet_widget_checkbox_init (SheetWidgetCheckbox
*swc
)
2360 sheet_widget_checkbox_init_full (swc
, NULL
, NULL
);
2364 sheet_widget_checkbox_finalize (GObject
*obj
)
2366 SheetWidgetCheckbox
*swc
= GNM_SOW_CHECKBOX (obj
);
2368 g_return_if_fail (swc
!= NULL
);
2370 g_free (swc
->label
);
2373 dependent_set_expr (&swc
->dep
, NULL
);
2375 sheet_object_widget_class
->finalize (obj
);
2379 cb_checkbox_toggled (GtkToggleButton
*button
, SheetWidgetCheckbox
*swc
)
2383 if (swc
->being_updated
)
2385 swc
->value
= gtk_toggle_button_get_active (button
);
2386 sheet_widget_checkbox_set_active (swc
);
2388 if (so_get_ref (GNM_SO (swc
), &ref
, TRUE
) != NULL
) {
2389 gboolean new_val
= gtk_toggle_button_get_active (button
);
2390 cmd_so_set_value (widget_wbc (GTK_WIDGET (button
)),
2391 /* FIXME: This text sucks: */
2392 _("Clicking checkbox"),
2393 &ref
, value_new_bool (new_val
),
2394 sheet_object_get_sheet (GNM_SO (swc
)));
2399 sheet_widget_checkbox_create_widget (SheetObjectWidget
*sow
)
2401 SheetWidgetCheckbox
*swc
= GNM_SOW_CHECKBOX (sow
);
2404 g_return_val_if_fail (swc
!= NULL
, NULL
);
2406 button
= gtk_check_button_new_with_label (swc
->label
);
2407 gtk_widget_set_can_focus (button
, FALSE
);
2408 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button
), swc
->value
);
2409 g_signal_connect (G_OBJECT (button
),
2411 G_CALLBACK (cb_checkbox_toggled
), swc
);
2417 sheet_widget_checkbox_copy (SheetObject
*dst
, SheetObject
const *src
)
2419 SheetWidgetCheckbox
const *src_swc
= GNM_SOW_CHECKBOX (src
);
2420 SheetWidgetCheckbox
*dst_swc
= GNM_SOW_CHECKBOX (dst
);
2422 sheet_widget_checkbox_init_full (dst_swc
,
2423 so_get_ref (src
, &ref
, FALSE
),
2425 dst_swc
->value
= src_swc
->value
;
2430 GnmExprEntry
*expression
;
2434 GtkWidget
*old_focus
;
2437 SheetWidgetCheckbox
*swc
;
2439 } CheckboxConfigState
;
2442 cb_checkbox_set_focus (G_GNUC_UNUSED GtkWidget
*window
, GtkWidget
*focus_widget
,
2443 CheckboxConfigState
*state
)
2447 /* Note: half of the set-focus action is handle by the default
2448 * callback installed by wbc_gtk_attach_guru. */
2450 ofp
= state
->old_focus
2451 ? gtk_widget_get_parent (state
->old_focus
)
2454 /* Force an update of the content in case it needs tweaking (eg make it
2456 if (ofp
&& GNM_EXPR_ENTRY_IS (ofp
)) {
2458 GnmExprTop
const *texpr
= gnm_expr_entry_parse (
2459 GNM_EXPR_ENTRY (ofp
),
2460 parse_pos_init_sheet (&pp
, state
->sheet
),
2461 NULL
, FALSE
, GNM_EXPR_PARSE_DEFAULT
);
2463 gnm_expr_top_unref (texpr
);
2465 state
->old_focus
= focus_widget
;
2469 cb_checkbox_config_destroy (CheckboxConfigState
*state
)
2471 g_return_if_fail (state
!= NULL
);
2473 g_free (state
->old_label
);
2474 state
->old_label
= NULL
;
2475 state
->dialog
= NULL
;
2480 cb_checkbox_config_ok_clicked (G_GNUC_UNUSED GtkWidget
*button
, CheckboxConfigState
*state
)
2482 SheetObject
*so
= GNM_SO (state
->swc
);
2484 GnmExprTop
const *texpr
= gnm_expr_entry_parse (state
->expression
,
2485 parse_pos_init_sheet (&pp
, so
->sheet
),
2486 NULL
, FALSE
, GNM_EXPR_PARSE_DEFAULT
);
2487 gchar
const *text
= gtk_entry_get_text(GTK_ENTRY(state
->label
));
2489 cmd_so_set_checkbox (GNM_WBC (state
->wbcg
), so
,
2490 texpr
, g_strdup (state
->old_label
), g_strdup (text
));
2492 gtk_widget_destroy (state
->dialog
);
2496 cb_checkbox_config_cancel_clicked (G_GNUC_UNUSED GtkWidget
*button
, CheckboxConfigState
*state
)
2498 sheet_widget_checkbox_set_label (GNM_SO (state
->swc
),
2500 gtk_widget_destroy (state
->dialog
);
2504 cb_checkbox_label_changed (GtkEntry
*entry
, CheckboxConfigState
*state
)
2506 sheet_widget_checkbox_set_label (GNM_SO (state
->swc
),
2507 gtk_entry_get_text (entry
));
2511 sheet_widget_checkbox_user_config (SheetObject
*so
, SheetControl
*sc
)
2513 SheetWidgetCheckbox
*swc
= GNM_SOW_CHECKBOX (so
);
2514 WBCGtk
*wbcg
= scg_wbcg (GNM_SCG (sc
));
2515 CheckboxConfigState
*state
;
2519 g_return_if_fail (swc
!= NULL
);
2521 /* Only pop up one copy per workbook */
2522 if (gnm_dialog_raise_if_exists (wbcg
, SHEET_OBJECT_CONFIG_KEY
))
2525 gui
= gnm_gtk_builder_load ("res:ui/so-checkbox.ui", NULL
, GO_CMD_CONTEXT (wbcg
));
2528 state
= g_new (CheckboxConfigState
, 1);
2531 state
->sheet
= sc_sheet (sc
);
2532 state
->old_focus
= NULL
;
2533 state
->old_label
= g_strdup (swc
->label
);
2534 state
->dialog
= go_gtk_builder_get_widget (gui
, "SO-Checkbox");
2536 grid
= go_gtk_builder_get_widget (gui
, "main-grid");
2538 state
->expression
= gnm_expr_entry_new (wbcg
, TRUE
);
2539 gnm_expr_entry_set_flags (state
->expression
,
2540 GNM_EE_FORCE_ABS_REF
| GNM_EE_SHEET_OPTIONAL
| GNM_EE_SINGLE_RANGE
,
2542 gnm_expr_entry_load_from_dep (state
->expression
, &swc
->dep
);
2543 go_atk_setup_label (go_gtk_builder_get_widget (gui
, "label_linkto"),
2544 GTK_WIDGET (state
->expression
));
2545 gtk_grid_attach (GTK_GRID (grid
),
2546 GTK_WIDGET (state
->expression
), 1, 0, 1, 1);
2547 gtk_widget_show (GTK_WIDGET (state
->expression
));
2549 state
->label
= go_gtk_builder_get_widget (gui
, "label_entry");
2550 gtk_entry_set_text (GTK_ENTRY (state
->label
), swc
->label
);
2551 gtk_editable_select_region (GTK_EDITABLE(state
->label
), 0, -1);
2552 gnm_editable_enters (GTK_WINDOW (state
->dialog
),
2553 GTK_WIDGET (state
->expression
));
2554 gnm_editable_enters (GTK_WINDOW (state
->dialog
),
2555 GTK_WIDGET (state
->label
));
2557 g_signal_connect (G_OBJECT (state
->label
),
2559 G_CALLBACK (cb_checkbox_label_changed
), state
);
2560 g_signal_connect (G_OBJECT (go_gtk_builder_get_widget (gui
, "ok_button")),
2562 G_CALLBACK (cb_checkbox_config_ok_clicked
), state
);
2563 g_signal_connect (G_OBJECT (go_gtk_builder_get_widget (gui
, "cancel_button")),
2565 G_CALLBACK (cb_checkbox_config_cancel_clicked
), state
);
2567 gnm_init_help_button (
2568 go_gtk_builder_get_widget (gui
, "help_button"),
2569 GNUMERIC_HELP_LINK_SO_CHECKBOX
);
2571 gnm_keyed_dialog (state
->wbcg
, GTK_WINDOW (state
->dialog
),
2572 SHEET_OBJECT_CONFIG_KEY
);
2574 wbc_gtk_attach_guru (state
->wbcg
, state
->dialog
);
2575 g_object_set_data_full (G_OBJECT (state
->dialog
),
2576 "state", state
, (GDestroyNotify
) cb_checkbox_config_destroy
);
2578 /* Note: half of the set-focus action is handle by the default */
2579 /* callback installed by wbc_gtk_attach_guru */
2580 g_signal_connect (G_OBJECT (state
->dialog
), "set-focus",
2581 G_CALLBACK (cb_checkbox_set_focus
), state
);
2582 g_object_unref (gui
);
2584 gtk_widget_show (state
->dialog
);
2588 sheet_widget_checkbox_set_sheet (SheetObject
*so
, Sheet
*sheet
)
2590 SheetWidgetCheckbox
*swc
= GNM_SOW_CHECKBOX (so
);
2592 dependent_set_sheet (&swc
->dep
, sheet
);
2593 sheet_widget_checkbox_set_active (swc
);
2599 sheet_widget_checkbox_foreach_dep (SheetObject
*so
,
2600 SheetObjectForeachDepFunc func
,
2603 SheetWidgetCheckbox
*swc
= GNM_SOW_CHECKBOX (so
);
2604 func (&swc
->dep
, so
, user
);
2608 sheet_widget_checkbox_write_xml_sax (SheetObject
const *so
, GsfXMLOut
*output
,
2609 GnmConventions
const *convs
)
2611 SheetWidgetCheckbox
const *swc
= GNM_SOW_CHECKBOX (so
);
2612 gsf_xml_out_add_cstr (output
, "Label", swc
->label
);
2613 gsf_xml_out_add_int (output
, "Value", swc
->value
);
2614 sax_write_dep (output
, &swc
->dep
, "Input", convs
);
2618 sheet_widget_checkbox_prep_sax_parser (SheetObject
*so
, GsfXMLIn
*xin
,
2619 xmlChar
const **attrs
,
2620 GnmConventions
const *convs
)
2622 SheetWidgetCheckbox
*swc
= GNM_SOW_CHECKBOX (so
);
2624 for (; attrs
!= NULL
&& attrs
[0] && attrs
[1] ; attrs
+= 2)
2625 if (attr_eq (attrs
[0], "Label")) {
2626 g_free (swc
->label
);
2627 swc
->label
= g_strdup (CXML2C (attrs
[1]));
2628 } else if (gnm_xml_attr_int (attrs
, "Value", &swc
->value
))
2630 else if (sax_read_dep (attrs
, "Input", &swc
->dep
, xin
, convs
))
2635 sheet_widget_checkbox_set_link (SheetObject
*so
, GnmExprTop
const *texpr
)
2637 SheetWidgetCheckbox
*swc
= GNM_SOW_CHECKBOX (so
);
2638 dependent_set_expr (&swc
->dep
, texpr
);
2639 if (texpr
&& swc
->dep
.sheet
)
2640 dependent_link (&swc
->dep
);
2644 sheet_widget_checkbox_get_link (SheetObject
*so
)
2646 SheetWidgetCheckbox
*swc
= GNM_SOW_CHECKBOX (so
);
2647 GnmExprTop
const *texpr
= swc
->dep
.texpr
;
2650 gnm_expr_top_ref (texpr
);
2657 sheet_widget_checkbox_set_label (SheetObject
*so
, char const *str
)
2660 SheetWidgetCheckbox
*swc
= GNM_SOW_CHECKBOX (so
);
2663 if (go_str_compare (str
, swc
->label
) == 0)
2666 new_label
= g_strdup (str
);
2667 g_free (swc
->label
);
2668 swc
->label
= new_label
;
2670 for (list
= swc
->sow
.so
.realized_list
; list
; list
= list
->next
) {
2671 SheetObjectView
*view
= list
->data
;
2672 GocWidget
*item
= get_goc_widget (view
);
2673 gtk_button_set_label (GTK_BUTTON (item
->widget
), swc
->label
);
2678 sheet_widget_checkbox_draw_cairo (SheetObject
const *so
, cairo_t
*cr
,
2679 double width
, double height
)
2681 SheetWidgetCheckbox
const *swc
= GNM_SOW_CHECKBOX (so
);
2682 double halfheight
= height
/2;
2683 double dx
= 8., dxh
, pm
;
2686 pm
= MIN (height
- 2, width
- 12);
2692 cairo_set_line_width (cr
, 0.5);
2693 cairo_set_source_rgb(cr
, 1.0, 1.0, 1.0);
2695 cairo_new_path (cr
);
2696 cairo_move_to (cr
, dxh
, halfheight
- dxh
);
2697 cairo_rel_line_to (cr
, 0, dx
);
2698 cairo_rel_line_to (cr
, dx
, 0);
2699 cairo_rel_line_to (cr
, 0., -dx
);
2700 cairo_rel_line_to (cr
, -dx
, 0.);
2701 cairo_close_path (cr
);
2702 cairo_fill_preserve (cr
);
2703 cairo_set_source_rgb(cr
, 0.0, 0.0, 0.0);
2707 cairo_new_path (cr
);
2708 cairo_move_to (cr
, dxh
, halfheight
- dxh
);
2709 cairo_rel_line_to (cr
, dx
, dx
);
2710 cairo_rel_line_to (cr
, -dx
, 0.);
2711 cairo_rel_line_to (cr
, dx
, -dx
);
2712 cairo_rel_line_to (cr
, -dx
, 0.);
2713 cairo_close_path (cr
);
2714 cairo_set_line_join (cr
, CAIRO_LINE_JOIN_BEVEL
);
2718 cairo_move_to (cr
, 2 * dx
, halfheight
);
2720 pw
= width
- 2 * dx
;
2723 draw_cairo_text (cr
, swc
->label
, &pw
, &ph
, TRUE
, FALSE
, TRUE
, 0, TRUE
);
2725 cairo_new_path (cr
);
2730 SOW_MAKE_TYPE (checkbox
, Checkbox
,
2731 sheet_widget_checkbox_user_config
,
2732 sheet_widget_checkbox_set_sheet
,
2734 sheet_widget_checkbox_foreach_dep
,
2735 sheet_widget_checkbox_copy
,
2736 sheet_widget_checkbox_write_xml_sax
,
2737 sheet_widget_checkbox_prep_sax_parser
,
2738 sheet_widget_checkbox_get_property
,
2739 sheet_widget_checkbox_set_property
,
2740 sheet_widget_checkbox_draw_cairo
,
2742 g_object_class_install_property
2743 (object_class
, SOC_PROP_ACTIVE
,
2744 g_param_spec_boolean ("active", NULL
, NULL
,
2746 GSF_PARAM_STATIC
| G_PARAM_READWRITE
));
2747 g_object_class_install_property
2748 (object_class
, SOC_PROP_TEXT
,
2749 g_param_spec_string ("text", NULL
, NULL
, NULL
,
2750 GSF_PARAM_STATIC
| G_PARAM_READWRITE
));
2751 g_object_class_install_property
2752 (object_class
, SOC_PROP_MARKUP
,
2753 g_param_spec_boxed ("markup", NULL
, NULL
, PANGO_TYPE_ATTR_LIST
,
2754 GSF_PARAM_STATIC
| G_PARAM_READWRITE
));
2757 /****************************************************************************/
2758 typedef SheetWidgetCheckbox SheetWidgetToggleButton
;
2759 typedef SheetWidgetCheckboxClass SheetWidgetToggleButtonClass
;
2761 sheet_widget_toggle_button_create_widget (SheetObjectWidget
*sow
)
2763 SheetWidgetCheckbox
*swc
= GNM_SOW_CHECKBOX (sow
);
2764 GtkWidget
*button
= gtk_toggle_button_new_with_label (swc
->label
);
2765 gtk_widget_set_can_focus (button
, FALSE
);
2766 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button
), swc
->value
);
2767 g_signal_connect (G_OBJECT (button
),
2769 G_CALLBACK (cb_checkbox_toggled
), swc
);
2773 sheet_widget_toggle_button_class_init (SheetObjectWidgetClass
*sow_class
)
2775 sow_class
->create_widget
= &sheet_widget_toggle_button_create_widget
;
2778 GSF_CLASS (SheetWidgetToggleButton
, sheet_widget_toggle_button
,
2779 &sheet_widget_toggle_button_class_init
, NULL
,
2780 GNM_SOW_CHECKBOX_TYPE
)
2782 /****************************************************************************/
2784 #define GNM_SOW_RADIO_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNM_SOW_RADIO_BUTTON_TYPE, SheetWidgetRadioButton))
2785 #define DEP_TO_RADIO_BUTTON(d_ptr) (SheetWidgetRadioButton *)(((char *)d_ptr) - G_STRUCT_OFFSET(SheetWidgetRadioButton, dep))
2788 SheetObjectWidget sow
;
2790 gboolean being_updated
;
2795 } SheetWidgetRadioButton
;
2796 typedef SheetObjectWidgetClass SheetWidgetRadioButtonClass
;
2807 sheet_widget_radio_button_set_active (SheetWidgetRadioButton
*swrb
,
2812 if (swrb
->active
== active
)
2814 swrb
->active
= active
;
2816 swrb
->being_updated
= TRUE
;
2818 for (ptr
= swrb
->sow
.so
.realized_list
; ptr
!= NULL
; ptr
= ptr
->next
) {
2819 SheetObjectView
*view
= ptr
->data
;
2820 GocWidget
*item
= get_goc_widget (view
);
2821 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item
->widget
),
2825 g_object_notify (G_OBJECT (swrb
), "active");
2827 swrb
->being_updated
= FALSE
;
2832 sheet_widget_radio_button_get_property (GObject
*obj
, guint param_id
,
2833 GValue
*value
, GParamSpec
*pspec
)
2835 SheetWidgetRadioButton
*swrb
= GNM_SOW_RADIO_BUTTON (obj
);
2838 case SOR_PROP_ACTIVE
:
2839 g_value_set_boolean (value
, swrb
->active
);
2842 g_value_set_string (value
, swrb
->label
);
2844 case SOR_PROP_MARKUP
:
2845 g_value_set_boxed (value
, NULL
); /* swrb->markup */
2847 case SOR_PROP_VALUE
:
2848 g_value_set_boxed (value
, swrb
->value
);
2851 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj
, param_id
, pspec
);
2857 sheet_widget_radio_button_set_property (GObject
*obj
, guint param_id
,
2858 GValue
const *value
, GParamSpec
*pspec
)
2860 SheetWidgetRadioButton
*swrb
= GNM_SOW_RADIO_BUTTON (obj
);
2863 case SOR_PROP_ACTIVE
:
2864 sheet_widget_radio_button_set_active (swrb
,
2865 g_value_get_boolean (value
));
2868 sheet_widget_radio_button_set_label (GNM_SO (swrb
),
2869 g_value_get_string (value
));
2871 case SOR_PROP_MARKUP
:
2873 sheet_widget_radio_button_set_markup (GNM_SO (swrb
),
2874 g_value_peek_pointer (value
));
2877 case SOR_PROP_VALUE
:
2878 sheet_widget_radio_button_set_value (GNM_SO (swrb
),
2879 g_value_get_boxed (value
));
2882 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj
, param_id
, pspec
);
2888 sheet_widget_radio_button_get_value (SheetObject
*so
)
2890 SheetWidgetRadioButton
*swrb
;
2892 g_return_val_if_fail (GNM_IS_SOW_RADIO_BUTTON (so
), NULL
);
2894 swrb
= GNM_SOW_RADIO_BUTTON (so
);
2899 sheet_widget_radio_button_set_value (SheetObject
*so
, GnmValue
const *val
)
2901 SheetWidgetRadioButton
*swrb
= GNM_SOW_RADIO_BUTTON (so
);
2903 value_release (swrb
->value
);
2904 swrb
->value
= value_dup (val
);
2908 radio_button_eval (GnmDependent
*dep
)
2912 SheetWidgetRadioButton
*swrb
= DEP_TO_RADIO_BUTTON (dep
);
2914 v
= gnm_expr_top_eval (dep
->texpr
, eval_pos_init_dep (&pos
, dep
),
2915 GNM_EXPR_EVAL_SCALAR_NON_EMPTY
);
2916 if (v
&& swrb
->value
) {
2917 gboolean active
= value_equal (swrb
->value
, v
);
2918 sheet_widget_radio_button_set_active (swrb
, active
);
2924 radio_button_debug_name (GnmDependent
const *dep
, GString
*target
)
2926 g_string_append_printf (target
, "RadioButton%p", (void *)dep
);
2929 static DEPENDENT_MAKE_TYPE (radio_button
, NULL
)
2932 sheet_widget_radio_button_init_full (SheetWidgetRadioButton
*swrb
,
2933 GnmCellRef
const *ref
,
2935 GnmValue
const *value
,
2938 g_return_if_fail (swrb
!= NULL
);
2940 swrb
->being_updated
= FALSE
;
2941 swrb
->label
= g_strdup (label
? label
: _("RadioButton"));
2942 swrb
->value
= value
? value_dup (value
) : value_new_empty ();
2943 swrb
->active
= active
;
2945 swrb
->dep
.sheet
= NULL
;
2946 swrb
->dep
.flags
= radio_button_get_dep_type ();
2947 swrb
->dep
.texpr
= (ref
!= NULL
)
2948 ? gnm_expr_top_new (gnm_expr_new_cellref (ref
))
2953 sheet_widget_radio_button_init (SheetWidgetRadioButton
*swrb
)
2955 sheet_widget_radio_button_init_full (swrb
, NULL
, NULL
, NULL
, TRUE
);
2959 sheet_widget_radio_button_finalize (GObject
*obj
)
2961 SheetWidgetRadioButton
*swrb
= GNM_SOW_RADIO_BUTTON (obj
);
2963 g_return_if_fail (swrb
!= NULL
);
2965 g_free (swrb
->label
);
2967 value_release (swrb
->value
);
2970 dependent_set_expr (&swrb
->dep
, NULL
);
2972 sheet_object_widget_class
->finalize (obj
);
2976 sheet_widget_radio_button_toggled (GtkToggleButton
*button
,
2977 SheetWidgetRadioButton
*swrb
)
2981 if (swrb
->being_updated
)
2983 swrb
->active
= gtk_toggle_button_get_active (button
);
2985 if (so_get_ref (GNM_SO (swrb
), &ref
, TRUE
) != NULL
) {
2986 cmd_so_set_value (widget_wbc (GTK_WIDGET (button
)),
2987 /* FIXME: This text sucks: */
2988 _("Clicking radiobutton"),
2989 &ref
, value_dup (swrb
->value
),
2990 sheet_object_get_sheet (GNM_SO (swrb
)));
2995 sheet_widget_radio_button_create_widget (SheetObjectWidget
*sow
)
2997 SheetWidgetRadioButton
*swrb
= GNM_SOW_RADIO_BUTTON (sow
);
2998 GtkWidget
*w
= g_object_new (GNM_TYPE_RADIO_BUTTON
,
2999 "label", swrb
->label
,
3002 gtk_widget_set_can_focus (w
, FALSE
);
3004 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w
), swrb
->active
);
3006 g_signal_connect (G_OBJECT (w
),
3008 G_CALLBACK (sheet_widget_radio_button_toggled
), sow
);
3013 sheet_widget_radio_button_copy (SheetObject
*dst
, SheetObject
const *src
)
3015 SheetWidgetRadioButton
const *src_swrb
= GNM_SOW_RADIO_BUTTON (src
);
3016 SheetWidgetRadioButton
*dst_swrb
= GNM_SOW_RADIO_BUTTON (dst
);
3019 sheet_widget_radio_button_init_full (dst_swrb
,
3020 so_get_ref (src
, &ref
, FALSE
),
3027 sheet_widget_radio_button_set_sheet (SheetObject
*so
, Sheet
*sheet
)
3029 SheetWidgetRadioButton
*swrb
= GNM_SOW_RADIO_BUTTON (so
);
3031 dependent_set_sheet (&swrb
->dep
, sheet
);
3037 sheet_widget_radio_button_foreach_dep (SheetObject
*so
,
3038 SheetObjectForeachDepFunc func
,
3041 SheetWidgetRadioButton
*swrb
= GNM_SOW_RADIO_BUTTON (so
);
3042 func (&swrb
->dep
, so
, user
);
3046 sheet_widget_radio_button_write_xml_sax (SheetObject
const *so
,
3048 GnmConventions
const *convs
)
3050 SheetWidgetRadioButton
const *swrb
= GNM_SOW_RADIO_BUTTON (so
);
3051 GString
*valstr
= g_string_new (NULL
);
3053 value_get_as_gstring (swrb
->value
, valstr
, convs
);
3055 gsf_xml_out_add_cstr (output
, "Label", swrb
->label
);
3056 gsf_xml_out_add_cstr (output
, "Value", valstr
->str
);
3057 gsf_xml_out_add_int (output
, "ValueType", swrb
->value
->v_any
.type
);
3058 gsf_xml_out_add_int (output
, "Active", swrb
->active
);
3059 sax_write_dep (output
, &swrb
->dep
, "Input", convs
);
3061 g_string_free (valstr
, TRUE
);
3065 sheet_widget_radio_button_prep_sax_parser (SheetObject
*so
, GsfXMLIn
*xin
,
3066 xmlChar
const **attrs
,
3067 GnmConventions
const *convs
)
3069 SheetWidgetRadioButton
*swrb
= GNM_SOW_RADIO_BUTTON (so
);
3070 const char *valstr
= NULL
;
3073 for (; attrs
!= NULL
&& attrs
[0] && attrs
[1] ; attrs
+= 2) {
3074 if (attr_eq (attrs
[0], "Label")) {
3075 g_free (swrb
->label
);
3076 swrb
->label
= g_strdup (CXML2C (attrs
[1]));
3077 } else if (attr_eq (attrs
[0], "Value")) {
3078 valstr
= CXML2C (attrs
[1]);
3079 } else if (gnm_xml_attr_bool (attrs
, "Active", &swrb
->active
) ||
3080 gnm_xml_attr_int (attrs
, "ValueType", &value_type
) ||
3081 sax_read_dep (attrs
, "Input", &swrb
->dep
, xin
, convs
))
3085 value_release (swrb
->value
);
3088 swrb
->value
= value_type
3089 ? value_new_from_string (value_type
, valstr
, NULL
, FALSE
)
3090 : format_match (valstr
, NULL
, NULL
);
3093 swrb
->value
= value_new_empty ();
3097 sheet_widget_radio_button_set_link (SheetObject
*so
, GnmExprTop
const *texpr
)
3099 SheetWidgetRadioButton
*swrb
= GNM_SOW_RADIO_BUTTON (so
);
3100 dependent_set_expr (&swrb
->dep
, texpr
);
3101 if (texpr
&& swrb
->dep
.sheet
)
3102 dependent_link (&swrb
->dep
);
3106 sheet_widget_radio_button_get_link (SheetObject
*so
)
3108 SheetWidgetRadioButton
*swrb
= GNM_SOW_RADIO_BUTTON (so
);
3109 GnmExprTop
const *texpr
= swrb
->dep
.texpr
;
3112 gnm_expr_top_ref (texpr
);
3118 sheet_widget_radio_button_set_label (SheetObject
*so
, char const *str
)
3121 SheetWidgetRadioButton
*swrb
= GNM_SOW_RADIO_BUTTON (so
);
3124 if (go_str_compare (str
, swrb
->label
) == 0)
3127 new_label
= g_strdup (str
);
3128 g_free (swrb
->label
);
3129 swrb
->label
= new_label
;
3131 for (list
= swrb
->sow
.so
.realized_list
; list
; list
= list
->next
) {
3132 SheetObjectView
*view
= list
->data
;
3133 GocWidget
*item
= get_goc_widget (view
);
3134 gtk_button_set_label (GTK_BUTTON (item
->widget
), swrb
->label
);
3141 GnmExprEntry
*expression
;
3142 GtkWidget
*label
, *value
;
3145 GnmValue
*old_value
;
3146 GtkWidget
*old_focus
;
3149 SheetWidgetRadioButton
*swrb
;
3151 } RadioButtonConfigState
;
3154 cb_radio_button_set_focus (G_GNUC_UNUSED GtkWidget
*window
, GtkWidget
*focus_widget
,
3155 RadioButtonConfigState
*state
)
3159 /* Note: half of the set-focus action is handle by the default
3160 * callback installed by wbc_gtk_attach_guru */
3162 ofp
= state
->old_focus
3163 ? gtk_widget_get_parent (state
->old_focus
)
3166 /* Force an update of the content in case it needs tweaking (eg make it
3168 if (ofp
&& GNM_EXPR_ENTRY_IS (ofp
)) {
3170 GnmExprTop
const *texpr
= gnm_expr_entry_parse (
3171 GNM_EXPR_ENTRY (ofp
),
3172 parse_pos_init_sheet (&pp
, state
->sheet
),
3173 NULL
, FALSE
, GNM_EXPR_PARSE_DEFAULT
);
3175 gnm_expr_top_unref (texpr
);
3177 state
->old_focus
= focus_widget
;
3181 cb_radio_button_config_destroy (RadioButtonConfigState
*state
)
3183 g_return_if_fail (state
!= NULL
);
3185 g_free (state
->old_label
);
3186 state
->old_label
= NULL
;
3188 value_release (state
->old_value
);
3189 state
->old_value
= NULL
;
3191 state
->dialog
= NULL
;
3197 so_parse_value (SheetObject
*so
, const char *s
)
3199 Sheet
*sheet
= so
->sheet
;
3200 return format_match (s
, NULL
, sheet_date_conv (sheet
));
3204 cb_radio_button_config_ok_clicked (G_GNUC_UNUSED GtkWidget
*button
, RadioButtonConfigState
*state
)
3206 SheetObject
*so
= GNM_SO (state
->swrb
);
3208 GnmExprTop
const *texpr
= gnm_expr_entry_parse
3210 parse_pos_init_sheet (&pp
, so
->sheet
),
3211 NULL
, FALSE
, GNM_EXPR_PARSE_DEFAULT
);
3212 gchar
const *text
= gtk_entry_get_text (GTK_ENTRY (state
->label
));
3213 gchar
const *val
= gtk_entry_get_text (GTK_ENTRY (state
->value
));
3214 GnmValue
*new_val
= so_parse_value (so
, val
);
3216 cmd_so_set_radio_button (GNM_WBC (state
->wbcg
), so
,
3218 g_strdup (state
->old_label
), g_strdup (text
),
3219 value_dup (state
->old_value
), new_val
);
3221 gtk_widget_destroy (state
->dialog
);
3225 cb_radio_button_config_cancel_clicked (G_GNUC_UNUSED GtkWidget
*button
, RadioButtonConfigState
*state
)
3227 sheet_widget_radio_button_set_label (GNM_SO (state
->swrb
),
3229 sheet_widget_radio_button_set_value (GNM_SO (state
->swrb
),
3231 gtk_widget_destroy (state
->dialog
);
3235 cb_radio_button_label_changed (GtkEntry
*entry
, RadioButtonConfigState
*state
)
3237 sheet_widget_radio_button_set_label (GNM_SO (state
->swrb
),
3238 gtk_entry_get_text (entry
));
3242 cb_radio_button_value_changed (GtkEntry
*entry
, RadioButtonConfigState
*state
)
3244 const char *text
= gtk_entry_get_text (entry
);
3245 SheetObject
*so
= GNM_SO (state
->swrb
);
3246 GnmValue
*val
= so_parse_value (so
, text
);
3248 sheet_widget_radio_button_set_value (so
, val
);
3249 value_release (val
);
3253 sheet_widget_radio_button_user_config (SheetObject
*so
, SheetControl
*sc
)
3255 SheetWidgetRadioButton
*swrb
= GNM_SOW_RADIO_BUTTON (so
);
3256 WBCGtk
*wbcg
= scg_wbcg (GNM_SCG (sc
));
3257 RadioButtonConfigState
*state
;
3262 g_return_if_fail (swrb
!= NULL
);
3264 /* Only pop up one copy per workbook */
3265 if (gnm_dialog_raise_if_exists (wbcg
, SHEET_OBJECT_CONFIG_KEY
))
3268 gui
= gnm_gtk_builder_load ("res:ui/so-radiobutton.ui", NULL
, GO_CMD_CONTEXT (wbcg
));
3271 state
= g_new (RadioButtonConfigState
, 1);
3274 state
->sheet
= sc_sheet (sc
);
3275 state
->old_focus
= NULL
;
3276 state
->old_label
= g_strdup (swrb
->label
);
3277 state
->old_value
= value_dup (swrb
->value
);
3278 state
->dialog
= go_gtk_builder_get_widget (gui
, "SO-Radiobutton");
3280 grid
= go_gtk_builder_get_widget (gui
, "main-grid");
3282 state
->expression
= gnm_expr_entry_new (wbcg
, TRUE
);
3283 gnm_expr_entry_set_flags (state
->expression
,
3284 GNM_EE_FORCE_ABS_REF
| GNM_EE_SHEET_OPTIONAL
| GNM_EE_SINGLE_RANGE
,
3286 gnm_expr_entry_load_from_dep (state
->expression
, &swrb
->dep
);
3287 go_atk_setup_label (go_gtk_builder_get_widget (gui
, "label_linkto"),
3288 GTK_WIDGET (state
->expression
));
3289 gtk_grid_attach (GTK_GRID (grid
),
3290 GTK_WIDGET (state
->expression
), 1, 0, 1, 1);
3291 gtk_widget_show (GTK_WIDGET (state
->expression
));
3293 state
->label
= go_gtk_builder_get_widget (gui
, "label_entry");
3294 gtk_entry_set_text (GTK_ENTRY (state
->label
), swrb
->label
);
3295 gtk_editable_select_region (GTK_EDITABLE(state
->label
), 0, -1);
3296 state
->value
= go_gtk_builder_get_widget (gui
, "value_entry");
3298 valstr
= g_string_new (NULL
);
3299 value_get_as_gstring (swrb
->value
, valstr
, so
->sheet
->convs
);
3300 gtk_entry_set_text (GTK_ENTRY (state
->value
), valstr
->str
);
3301 g_string_free (valstr
, TRUE
);
3303 gnm_editable_enters (GTK_WINDOW (state
->dialog
),
3304 GTK_WIDGET (state
->expression
));
3305 gnm_editable_enters (GTK_WINDOW (state
->dialog
),
3306 GTK_WIDGET (state
->label
));
3307 gnm_editable_enters (GTK_WINDOW (state
->dialog
),
3308 GTK_WIDGET (state
->value
));
3310 g_signal_connect (G_OBJECT (state
->label
),
3312 G_CALLBACK (cb_radio_button_label_changed
), state
);
3313 g_signal_connect (G_OBJECT (state
->value
),
3315 G_CALLBACK (cb_radio_button_value_changed
), state
);
3316 g_signal_connect (G_OBJECT (go_gtk_builder_get_widget (gui
, "ok_button")),
3318 G_CALLBACK (cb_radio_button_config_ok_clicked
), state
);
3319 g_signal_connect (G_OBJECT (go_gtk_builder_get_widget (gui
, "cancel_button")),
3321 G_CALLBACK (cb_radio_button_config_cancel_clicked
), state
);
3323 gnm_init_help_button (
3324 go_gtk_builder_get_widget (gui
, "help_button"),
3325 GNUMERIC_HELP_LINK_SO_RADIO_BUTTON
);
3327 gnm_keyed_dialog (state
->wbcg
, GTK_WINDOW (state
->dialog
),
3328 SHEET_OBJECT_CONFIG_KEY
);
3330 wbc_gtk_attach_guru (state
->wbcg
, state
->dialog
);
3331 g_object_set_data_full (G_OBJECT (state
->dialog
),
3332 "state", state
, (GDestroyNotify
) cb_radio_button_config_destroy
);
3333 g_object_unref (gui
);
3335 /* Note: half of the set-focus action is handle by the default */
3336 /* callback installed by wbc_gtk_attach_guru */
3337 g_signal_connect (G_OBJECT (state
->dialog
), "set-focus",
3338 G_CALLBACK (cb_radio_button_set_focus
), state
);
3340 gtk_widget_show (state
->dialog
);
3344 sheet_widget_radio_button_draw_cairo (SheetObject
const *so
, cairo_t
*cr
,
3345 G_GNUC_UNUSED
double width
, double height
)
3347 SheetWidgetRadioButton
const *swr
= GNM_SOW_RADIO_BUTTON (so
);
3348 double halfheight
= height
/2;
3349 double dx
= 8., dxh
, pm
;
3352 pm
= MIN (height
- 2, width
- 12);
3358 cairo_set_line_width (cr
, 0.5);
3359 cairo_set_source_rgb(cr
, 1.0, 1.0, 1.0);
3361 cairo_new_path (cr
);
3362 cairo_move_to (cr
, dxh
+ dx
, halfheight
);
3363 cairo_arc (cr
, dx
, halfheight
, dxh
, 0., 2*M_PI
);
3364 cairo_close_path (cr
);
3365 cairo_fill_preserve (cr
);
3366 cairo_set_source_rgb(cr
, 0.0, 0.0, 0.0);
3370 cairo_new_path (cr
);
3371 cairo_move_to (cr
, dx
+ dxh
/2 + 0.5, halfheight
);
3372 cairo_arc (cr
, dx
, halfheight
, dxh
/2 + 0.5, 0., 2*M_PI
);
3373 cairo_close_path (cr
);
3377 cairo_move_to (cr
, 2 * dx
, halfheight
);
3379 pw
= width
- 2 * dx
;
3382 draw_cairo_text (cr
, swr
->label
, &pw
, &ph
, TRUE
, FALSE
, TRUE
, 0, TRUE
);
3384 cairo_new_path (cr
);
3388 SOW_MAKE_TYPE (radio_button
, RadioButton
,
3389 sheet_widget_radio_button_user_config
,
3390 sheet_widget_radio_button_set_sheet
,
3392 sheet_widget_radio_button_foreach_dep
,
3393 sheet_widget_radio_button_copy
,
3394 sheet_widget_radio_button_write_xml_sax
,
3395 sheet_widget_radio_button_prep_sax_parser
,
3396 sheet_widget_radio_button_get_property
,
3397 sheet_widget_radio_button_set_property
,
3398 sheet_widget_radio_button_draw_cairo
,
3400 g_object_class_install_property
3401 (object_class
, SOR_PROP_ACTIVE
,
3402 g_param_spec_boolean ("active", NULL
, NULL
,
3404 GSF_PARAM_STATIC
| G_PARAM_READWRITE
));
3405 g_object_class_install_property
3406 (object_class
, SOR_PROP_TEXT
,
3407 g_param_spec_string ("text", NULL
, NULL
, NULL
,
3408 GSF_PARAM_STATIC
| G_PARAM_READWRITE
));
3409 g_object_class_install_property
3410 (object_class
, SOR_PROP_MARKUP
,
3411 g_param_spec_boxed ("markup", NULL
, NULL
, PANGO_TYPE_ATTR_LIST
,
3412 GSF_PARAM_STATIC
| G_PARAM_READWRITE
));
3413 g_object_class_install_property
3414 (object_class
, SOR_PROP_VALUE
,
3415 g_param_spec_boxed ("value", NULL
, NULL
,
3416 gnm_value_get_type (),
3417 GSF_PARAM_STATIC
| G_PARAM_READWRITE
));
3420 /****************************************************************************/
3422 #define GNM_SOW_LIST_BASE_TYPE (sheet_widget_list_base_get_type ())
3423 #define GNM_SOW_LIST_BASE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNM_SOW_LIST_BASE_TYPE, SheetWidgetListBase))
3424 #define DEP_TO_LIST_BASE_CONTENT(d_ptr) (SheetWidgetListBase *)(((char *)d_ptr) - G_STRUCT_OFFSET(SheetWidgetListBase, content_dep))
3425 #define DEP_TO_LIST_BASE_OUTPUT(d_ptr) (SheetWidgetListBase *)(((char *)d_ptr) - G_STRUCT_OFFSET(SheetWidgetListBase, output_dep))
3428 SheetObjectWidget sow
;
3430 GnmDependent content_dep
; /* content of the list */
3431 GnmDependent output_dep
; /* selected element */
3433 GtkTreeModel
*model
;
3435 gboolean result_as_index
;
3436 } SheetWidgetListBase
;
3438 SheetObjectWidgetClass base
;
3440 void (*model_changed
) (SheetWidgetListBase
*list
);
3441 void (*selection_changed
) (SheetWidgetListBase
*list
);
3442 } SheetWidgetListBaseClass
;
3445 LIST_BASE_MODEL_CHANGED
,
3446 LIST_BASE_SELECTION_CHANGED
,
3447 LIST_BASE_LAST_SIGNAL
3450 static guint list_base_signals
[LIST_BASE_LAST_SIGNAL
] = { 0 };
3451 static GType
sheet_widget_list_base_get_type (void);
3454 sheet_widget_list_base_set_selection (SheetWidgetListBase
*swl
, int selection
,
3455 WorkbookControl
*wbc
)
3459 if (selection
>= 0 && swl
->model
!= NULL
) {
3460 int n
= gtk_tree_model_iter_n_children (swl
->model
, NULL
);
3466 if (swl
->selection
!= selection
) {
3467 swl
->selection
= selection
;
3469 so_get_ref (GNM_SO (swl
), &ref
, TRUE
) != NULL
) {
3471 if (swl
->result_as_index
)
3472 v
= value_new_int (swl
->selection
);
3473 else if (selection
!= 0) {
3476 gtk_tree_model_iter_nth_child
3477 (swl
->model
, &iter
, NULL
, selection
- 1);
3478 gtk_tree_model_get (swl
->model
, &iter
,
3480 v
= value_new_string_nocopy (content
);
3482 v
= value_new_string ("");
3483 cmd_so_set_value (wbc
, _("Clicking in list"), &ref
, v
,
3484 sheet_object_get_sheet (GNM_SO (swl
)));
3486 g_signal_emit (G_OBJECT (swl
),
3487 list_base_signals
[LIST_BASE_SELECTION_CHANGED
], 0);
3492 sheet_widget_list_base_set_selection_value (SheetWidgetListBase
*swl
, GnmValue
*v
)
3495 int selection
= 0, i
= 1;
3497 if (swl
->model
!= NULL
&& gtk_tree_model_get_iter_first (swl
->model
, &iter
)) {
3498 char *str
= value_get_as_string (v
);
3502 gtk_tree_model_get (swl
->model
, &iter
,
3504 match
= 0 == g_ascii_strcasecmp (str
, content
);
3511 } while (gtk_tree_model_iter_next (swl
->model
, &iter
));
3515 if (swl
->selection
!= selection
) {
3516 swl
->selection
= selection
;
3517 g_signal_emit (G_OBJECT (swl
),
3518 list_base_signals
[LIST_BASE_SELECTION_CHANGED
], 0);
3523 list_output_eval (GnmDependent
*dep
)
3526 GnmValue
*v
= gnm_expr_top_eval (dep
->texpr
,
3527 eval_pos_init_dep (&pos
, dep
),
3528 GNM_EXPR_EVAL_SCALAR_NON_EMPTY
);
3529 SheetWidgetListBase
*swl
= DEP_TO_LIST_BASE_OUTPUT (dep
);
3531 if (swl
->result_as_index
)
3532 sheet_widget_list_base_set_selection
3533 (swl
, floor (value_get_as_float (v
)), NULL
);
3535 sheet_widget_list_base_set_selection_value (swl
, v
);
3540 list_output_debug_name (GnmDependent
const *dep
, GString
*target
)
3542 g_string_append_printf (target
, "ListOutput%p", (void *)dep
);
3545 static DEPENDENT_MAKE_TYPE (list_output
, NULL
)
3549 cb_collect (GnmValueIter
const *iter
, GtkListStore
*model
)
3551 GtkTreeIter list_iter
;
3553 gtk_list_store_append (model
, &list_iter
);
3554 if (NULL
!= iter
->v
) {
3555 GOFormat
const *fmt
= (NULL
!= iter
->cell_iter
)
3556 ? gnm_cell_get_format (iter
->cell_iter
->cell
) : NULL
;
3557 char *label
= format_value (fmt
, iter
->v
, -1, NULL
);
3558 gtk_list_store_set (model
, &list_iter
, 0, label
, -1);
3561 gtk_list_store_set (model
, &list_iter
, 0, "", -1);
3566 list_content_eval (GnmDependent
*dep
)
3568 SheetWidgetListBase
*swl
= DEP_TO_LIST_BASE_CONTENT (dep
);
3571 GtkListStore
*model
;
3573 if (dep
->texpr
!= NULL
) {
3574 v
= gnm_expr_top_eval (dep
->texpr
,
3575 eval_pos_init_dep (&ep
, dep
),
3576 GNM_EXPR_EVAL_PERMIT_NON_SCALAR
|
3577 GNM_EXPR_EVAL_PERMIT_EMPTY
);
3579 model
= gtk_list_store_new (1, G_TYPE_STRING
);
3581 value_area_foreach (v
, &ep
, CELL_ITER_ALL
,
3582 (GnmValueIterFunc
) cb_collect
, model
);
3586 if (NULL
!= swl
->model
)
3587 g_object_unref (swl
->model
);
3588 swl
->model
= GTK_TREE_MODEL (model
);
3589 g_signal_emit (G_OBJECT (swl
), list_base_signals
[LIST_BASE_MODEL_CHANGED
], 0);
3593 list_content_debug_name (GnmDependent
const *dep
, GString
*target
)
3595 g_string_append_printf (target
, "ListContent%p", (void *)dep
);
3598 static DEPENDENT_MAKE_TYPE (list_content
, NULL
)
3603 sheet_widget_list_base_init (SheetObjectWidget
*sow
)
3605 SheetWidgetListBase
*swl
= GNM_SOW_LIST_BASE (sow
);
3606 SheetObject
*so
= GNM_SO (sow
);
3608 so
->flags
&= ~SHEET_OBJECT_PRINT
;
3610 swl
->content_dep
.sheet
= NULL
;
3611 swl
->content_dep
.flags
= list_content_get_dep_type ();
3612 swl
->content_dep
.texpr
= NULL
;
3614 swl
->output_dep
.sheet
= NULL
;
3615 swl
->output_dep
.flags
= list_output_get_dep_type ();
3616 swl
->output_dep
.texpr
= NULL
;
3620 swl
->result_as_index
= TRUE
;
3624 sheet_widget_list_base_finalize (GObject
*obj
)
3626 SheetWidgetListBase
*swl
= GNM_SOW_LIST_BASE (obj
);
3627 dependent_set_expr (&swl
->content_dep
, NULL
);
3628 dependent_set_expr (&swl
->output_dep
, NULL
);
3629 if (swl
->model
!= NULL
) {
3630 g_object_unref (swl
->model
);
3633 sheet_object_widget_class
->finalize (obj
);
3637 sheet_widget_list_base_user_config (SheetObject
*so
, SheetControl
*sc
)
3639 dialog_so_list (scg_wbcg (GNM_SCG (sc
)), G_OBJECT (so
));
3642 sheet_widget_list_base_set_sheet (SheetObject
*so
, Sheet
*sheet
)
3644 SheetWidgetListBase
*swl
= GNM_SOW_LIST_BASE (so
);
3646 g_return_val_if_fail (swl
!= NULL
, TRUE
);
3647 g_return_val_if_fail (swl
->content_dep
.sheet
== NULL
, TRUE
);
3648 g_return_val_if_fail (swl
->output_dep
.sheet
== NULL
, TRUE
);
3650 dependent_set_sheet (&swl
->content_dep
, sheet
);
3651 dependent_set_sheet (&swl
->output_dep
, sheet
);
3653 list_content_eval (&swl
->content_dep
); /* populate the list */
3659 sheet_widget_list_base_foreach_dep (SheetObject
*so
,
3660 SheetObjectForeachDepFunc func
,
3663 SheetWidgetListBase
*swl
= GNM_SOW_LIST_BASE (so
);
3664 func (&swl
->content_dep
, so
, user
);
3665 func (&swl
->output_dep
, so
, user
);
3669 sheet_widget_list_base_write_xml_sax (SheetObject
const *so
, GsfXMLOut
*output
,
3670 GnmConventions
const *convs
)
3672 SheetWidgetListBase
const *swl
= GNM_SOW_LIST_BASE (so
);
3673 sax_write_dep (output
, &swl
->content_dep
, "Content", convs
);
3674 sax_write_dep (output
, &swl
->output_dep
, "Output", convs
);
3675 gsf_xml_out_add_int (output
, "OutputAsIndex", swl
->result_as_index
? 1 : 0);
3679 sheet_widget_list_base_prep_sax_parser (SheetObject
*so
, GsfXMLIn
*xin
,
3680 xmlChar
const **attrs
,
3681 GnmConventions
const *convs
)
3683 SheetWidgetListBase
*swl
= GNM_SOW_LIST_BASE (so
);
3685 for (; attrs
!= NULL
&& attrs
[0] && attrs
[1] ; attrs
+= 2)
3686 if (sax_read_dep (attrs
, "Content", &swl
->content_dep
, xin
, convs
))
3688 else if (sax_read_dep (attrs
, "Output", &swl
->output_dep
, xin
, convs
))
3690 else if (gnm_xml_attr_bool (attrs
, "OutputAsIndex", &swl
->result_as_index
))
3695 sheet_widget_list_base_create_widget (G_GNUC_UNUSED SheetObjectWidget
*sow
)
3697 g_warning("ERROR: sheet_widget_list_base_create_widget SHOULD NEVER BE CALLED (but it has been)!\n");
3698 return gtk_frame_new ("invisiwidget(WARNING: I AM A BUG!)");
3701 SOW_MAKE_TYPE (list_base
, ListBase
,
3702 sheet_widget_list_base_user_config
,
3703 sheet_widget_list_base_set_sheet
,
3705 sheet_widget_list_base_foreach_dep
,
3707 sheet_widget_list_base_write_xml_sax
,
3708 sheet_widget_list_base_prep_sax_parser
,
3711 sheet_widget_draw_cairo
,
3713 list_base_signals
[LIST_BASE_MODEL_CHANGED
] = g_signal_new ("model-changed",
3714 GNM_SOW_LIST_BASE_TYPE
,
3716 G_STRUCT_OFFSET (SheetWidgetListBaseClass
, model_changed
),
3718 g_cclosure_marshal_VOID__VOID
,
3720 list_base_signals
[LIST_BASE_SELECTION_CHANGED
] = g_signal_new ("selection-changed",
3721 GNM_SOW_LIST_BASE_TYPE
,
3723 G_STRUCT_OFFSET (SheetWidgetListBaseClass
, selection_changed
),
3725 g_cclosure_marshal_VOID__VOID
,
3730 sheet_widget_list_base_set_links (SheetObject
*so
,
3731 GnmExprTop
const *output
,
3732 GnmExprTop
const *content
)
3734 SheetWidgetListBase
*swl
= GNM_SOW_LIST_BASE (so
);
3735 dependent_set_expr (&swl
->output_dep
, output
);
3736 if (output
&& swl
->output_dep
.sheet
)
3737 dependent_link (&swl
->output_dep
);
3738 dependent_set_expr (&swl
->content_dep
, content
);
3739 if (content
&& swl
->content_dep
.sheet
) {
3740 dependent_link (&swl
->content_dep
);
3741 list_content_eval (&swl
->content_dep
); /* populate the list */
3746 sheet_widget_list_base_get_result_link (SheetObject
const *so
)
3748 SheetWidgetListBase
*swl
= GNM_SOW_LIST_BASE (so
);
3749 GnmExprTop
const *texpr
= swl
->output_dep
.texpr
;
3752 gnm_expr_top_ref (texpr
);
3758 sheet_widget_list_base_get_content_link (SheetObject
const *so
)
3760 SheetWidgetListBase
*swl
= GNM_SOW_LIST_BASE (so
);
3761 GnmExprTop
const *texpr
= swl
->content_dep
.texpr
;
3764 gnm_expr_top_ref (texpr
);
3770 sheet_widget_list_base_result_type_is_index (SheetObject
const *so
)
3772 SheetWidgetListBase
*swl
= GNM_SOW_LIST_BASE (so
);
3774 return swl
->result_as_index
;
3778 sheet_widget_list_base_set_result_type (SheetObject
*so
, gboolean as_index
)
3780 SheetWidgetListBase
*swl
= GNM_SOW_LIST_BASE (so
);
3782 if (swl
->result_as_index
== as_index
)
3785 swl
->result_as_index
= as_index
;
3790 * sheet_widget_list_base_get_adjustment:
3793 * Note: allocates a new adjustment.
3794 * Returns: (transfer full): the newly created #GtkAdjustment.
3797 sheet_widget_list_base_get_adjustment (SheetObject
*so
)
3799 SheetWidgetListBase
*swl
= GNM_SOW_LIST_BASE (so
);
3802 g_return_val_if_fail (swl
, NULL
);
3804 adj
= (GtkAdjustment
*)gtk_adjustment_new
3807 1 + gtk_tree_model_iter_n_children (swl
->model
, NULL
),
3811 g_object_ref_sink (adj
);
3816 /****************************************************************************/
3818 #define GNM_SOW_LIST(o) (G_TYPE_CHECK_INSTANCE_CAST((o), GNM_SOW_LIST_TYPE, SheetWidgetList))
3820 typedef SheetWidgetListBase SheetWidgetList
;
3821 typedef SheetWidgetListBaseClass SheetWidgetListClass
;
3824 cb_list_selection_changed (SheetWidgetListBase
*swl
,
3825 GtkTreeSelection
*selection
)
3827 if (swl
->selection
> 0) {
3828 GtkTreePath
*path
= gtk_tree_path_new_from_indices (swl
->selection
-1, -1);
3829 gtk_tree_selection_select_path (selection
, path
);
3830 gtk_tree_path_free (path
);
3832 gtk_tree_selection_unselect_all (selection
);
3836 cb_list_model_changed (SheetWidgetListBase
*swl
, GtkTreeView
*list
)
3838 int old_selection
= swl
->selection
;
3839 swl
->selection
= -1;
3840 gtk_tree_view_set_model (GTK_TREE_VIEW (list
), swl
->model
);
3841 sheet_widget_list_base_set_selection (swl
, old_selection
, NULL
);
3844 cb_selection_changed (GtkTreeSelection
*selection
,
3845 SheetWidgetListBase
*swl
)
3847 GtkWidget
*view
= (GtkWidget
*)gtk_tree_selection_get_tree_view (selection
);
3848 GnmSimpleCanvas
*scanvas
= GNM_SIMPLE_CANVAS (gtk_widget_get_ancestor (view
, GNM_SIMPLE_CANVAS_TYPE
));
3849 GtkTreeModel
*model
;
3852 if (swl
->selection
!= -1) {
3853 if (gtk_tree_selection_get_selected (selection
, &model
, &iter
)) {
3854 GtkTreePath
*path
= gtk_tree_model_get_path (model
, &iter
);
3856 pos
= *gtk_tree_path_get_indices (path
) + 1;
3857 gtk_tree_path_free (path
);
3860 sheet_widget_list_base_set_selection
3861 (swl
, pos
, scg_wbc (scanvas
->scg
));
3866 sheet_widget_list_create_widget (SheetObjectWidget
*sow
)
3868 SheetWidgetListBase
*swl
= GNM_SOW_LIST_BASE (sow
);
3869 GtkTreeSelection
*selection
;
3871 GtkWidget
*list
= gtk_tree_view_new_with_model (swl
->model
);
3872 GtkWidget
*sw
= gtk_scrolled_window_new (
3873 gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (list
)),
3874 gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (list
)));
3875 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw
),
3876 GTK_POLICY_AUTOMATIC
,
3878 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (list
), FALSE
);
3879 gtk_tree_view_append_column (GTK_TREE_VIEW (list
),
3880 gtk_tree_view_column_new_with_attributes ("ID",
3881 gtk_cell_renderer_text_new (), "text", 0,
3884 gtk_container_add (GTK_CONTAINER (sw
), list
);
3886 g_signal_connect_object (G_OBJECT (swl
), "model-changed",
3887 G_CALLBACK (cb_list_model_changed
), list
, 0);
3889 selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (list
));
3890 if ((swl
->model
!= NULL
) && (swl
->selection
> 0) &&
3891 gtk_tree_model_iter_nth_child (swl
->model
, &iter
, NULL
, swl
->selection
- 1))
3892 gtk_tree_selection_select_iter (selection
, &iter
);
3893 g_signal_connect_object (G_OBJECT (swl
), "selection-changed",
3894 G_CALLBACK (cb_list_selection_changed
), selection
, 0);
3895 g_signal_connect (selection
, "changed",
3896 G_CALLBACK (cb_selection_changed
), swl
);
3901 sheet_widget_list_draw_cairo (SheetObject
const *so
, cairo_t
*cr
,
3902 double width
, double height
)
3904 SheetWidgetListBase
*swl
= GNM_SOW_LIST_BASE (so
);
3907 cairo_set_line_width (cr
, 0.5);
3908 cairo_set_source_rgb(cr
, 0, 0, 0);
3910 cairo_new_path (cr
);
3911 cairo_move_to (cr
, 0, 0);
3912 cairo_line_to (cr
, width
, 0);
3913 cairo_line_to (cr
, width
, height
);
3914 cairo_line_to (cr
, 0, height
);
3915 cairo_close_path (cr
);
3918 cairo_new_path (cr
);
3919 cairo_move_to (cr
, width
- 10, 0);
3920 cairo_rel_line_to (cr
, 0, height
);
3923 cairo_set_source_rgb(cr
, 0.5, 0.5, 0.5);
3925 cairo_new_path (cr
);
3926 cairo_move_to (cr
, width
- 5 -3, height
- 12);
3927 cairo_rel_line_to (cr
, 6, 0);
3928 cairo_rel_line_to (cr
, -3, 8);
3929 cairo_close_path (cr
);
3932 cairo_new_path (cr
);
3933 cairo_move_to (cr
, width
- 5 -3, 12);
3934 cairo_rel_line_to (cr
, 6, 0);
3935 cairo_rel_line_to (cr
, -3, -8);
3936 cairo_close_path (cr
);
3939 if (swl
->model
!= NULL
) {
3941 GString
*str
= g_string_new (NULL
);
3942 int twidth
= width
, theight
= height
;
3945 cairo_new_path (cr
);
3946 cairo_rectangle (cr
, 2, 1, width
- 2 - 12, height
- 2);
3948 if (gtk_tree_model_get_iter_first (swl
->model
, &iter
))
3950 char *astr
= NULL
, *newline
;
3951 gtk_tree_model_get (swl
->model
, &iter
, 0, &astr
, -1);
3952 while (NULL
!= (newline
= strchr (astr
, '\n')))
3954 g_string_append (str
, astr
);
3955 g_string_append_c (str
, '\n');
3957 } while (gtk_tree_model_iter_next (swl
->model
, &iter
));
3959 cairo_translate (cr
, 4., 2.);
3961 draw_cairo_text (cr
, str
->str
, &twidth
, &theight
, FALSE
, FALSE
, FALSE
,
3962 swl
->selection
, FALSE
);
3964 g_string_free (str
, TRUE
);
3967 cairo_new_path (cr
);
3972 sheet_widget_list_class_init (SheetObjectWidgetClass
*sow_class
)
3974 SheetObjectClass
*so_class
= GNM_SO_CLASS (sow_class
);
3976 so_class
->draw_cairo
= &sheet_widget_list_draw_cairo
;
3977 sow_class
->create_widget
= &sheet_widget_list_create_widget
;
3980 GSF_CLASS (SheetWidgetList
, sheet_widget_list
,
3981 &sheet_widget_list_class_init
, NULL
,
3982 GNM_SOW_LIST_BASE_TYPE
)
3984 /****************************************************************************/
3986 #define GNM_SOW_COMBO(o) (G_TYPE_CHECK_INSTANCE_CAST((o), GNM_SOW_COMBO_TYPE, SheetWidgetCombo))
3988 typedef SheetWidgetListBase SheetWidgetCombo
;
3989 typedef SheetWidgetListBaseClass SheetWidgetComboClass
;
3992 cb_combo_selection_changed (SheetWidgetListBase
*swl
,
3995 int pos
= swl
->selection
- 1;
3997 gtk_entry_set_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (combo
))), "");
4000 gtk_combo_box_set_active (combo
, pos
);
4004 cb_combo_model_changed (SheetWidgetListBase
*swl
, GtkComboBox
*combo
)
4006 gtk_combo_box_set_model (GTK_COMBO_BOX (combo
), swl
->model
);
4008 /* we can not set this until we have a model,
4009 * but after that we can not reset it */
4010 if (gtk_combo_box_get_entry_text_column (GTK_COMBO_BOX (combo
)) < 0)
4011 gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX (combo
), 0);
4013 /* force entry to reload */
4014 cb_combo_selection_changed (swl
, combo
);
4018 cb_combo_changed (GtkComboBox
*combo
, SheetWidgetListBase
*swl
)
4020 int pos
= gtk_combo_box_get_active (combo
) + 1;
4021 sheet_widget_list_base_set_selection (swl
, pos
,
4022 widget_wbc (GTK_WIDGET (combo
)));
4026 sheet_widget_combo_create_widget (SheetObjectWidget
*sow
)
4028 SheetWidgetListBase
*swl
= GNM_SOW_LIST_BASE (sow
);
4029 GtkWidget
*widget
= gtk_event_box_new (), *combo
;
4031 combo
= gtk_combo_box_new_with_entry ();
4032 gtk_widget_set_can_focus (gtk_bin_get_child (GTK_BIN (combo
)),
4034 if (swl
->model
!= NULL
)
4035 g_object_set (G_OBJECT (combo
),
4036 "model", swl
->model
,
4037 "entry-text-column", 0,
4038 "active", swl
->selection
- 1,
4041 g_signal_connect_object (G_OBJECT (swl
), "model-changed",
4042 G_CALLBACK (cb_combo_model_changed
), combo
, 0);
4043 g_signal_connect_object (G_OBJECT (swl
), "selection-changed",
4044 G_CALLBACK (cb_combo_selection_changed
), combo
, 0);
4045 g_signal_connect (G_OBJECT (combo
), "changed",
4046 G_CALLBACK (cb_combo_changed
), swl
);
4048 gtk_container_add (GTK_CONTAINER (widget
), combo
);
4049 gtk_event_box_set_visible_window (GTK_EVENT_BOX (widget
), FALSE
);
4054 sheet_widget_combo_draw_cairo (SheetObject
const *so
, cairo_t
*cr
,
4055 double width
, double height
)
4057 SheetWidgetListBase
*swl
= GNM_SOW_LIST_BASE (so
);
4058 double halfheight
= height
/2;
4061 cairo_set_line_width (cr
, 0.5);
4062 cairo_set_source_rgb(cr
, 0, 0, 0);
4064 cairo_new_path (cr
);
4065 cairo_move_to (cr
, 0, 0);
4066 cairo_line_to (cr
, width
, 0);
4067 cairo_line_to (cr
, width
, height
);
4068 cairo_line_to (cr
, 0, height
);
4069 cairo_close_path (cr
);
4072 cairo_new_path (cr
);
4073 cairo_move_to (cr
, width
- 10, 0);
4074 cairo_rel_line_to (cr
, 0, height
);
4077 cairo_set_source_rgb(cr
, 0.5, 0.5, 0.5);
4079 cairo_new_path (cr
);
4080 cairo_move_to (cr
, width
- 5 -3, halfheight
- 4);
4081 cairo_rel_line_to (cr
, 6, 0);
4082 cairo_rel_line_to (cr
, -3, 8);
4083 cairo_close_path (cr
);
4086 cairo_set_source_rgb(cr
, 0, 0, 0);
4087 cairo_move_to (cr
, 4., halfheight
);
4089 if (swl
->model
!= NULL
) {
4091 if (gtk_tree_model_iter_nth_child (swl
->model
, &iter
, NULL
,
4092 swl
->selection
- 1)) {
4094 gtk_tree_model_get (swl
->model
, &iter
, 0, &str
, -1);
4095 draw_cairo_text (cr
, str
, NULL
, NULL
, TRUE
, FALSE
, TRUE
, 0, FALSE
);
4100 cairo_new_path (cr
);
4105 sheet_widget_combo_class_init (SheetObjectWidgetClass
*sow_class
)
4107 SheetObjectClass
*so_class
= GNM_SO_CLASS (sow_class
);
4109 so_class
->draw_cairo
= &sheet_widget_combo_draw_cairo
;
4110 sow_class
->create_widget
= &sheet_widget_combo_create_widget
;
4113 GSF_CLASS (SheetWidgetCombo
, sheet_widget_combo
,
4114 &sheet_widget_combo_class_init
, NULL
,
4115 GNM_SOW_LIST_BASE_TYPE
)
4121 /**************************************************************************/
4124 * sheet_widget_init_clases:
4127 * Initilize the classes for the sheet-object-widgets. We need to initalize
4128 * them before we try loading a sheet that might contain sheet-object-widgets
4131 sheet_object_widget_register (void)
4134 GNM_SOW_BUTTON_TYPE
;
4135 GNM_SOW_SCROLLBAR_TYPE
;
4136 GNM_SOW_CHECKBOX_TYPE
;
4137 GNM_SOW_RADIO_BUTTON_TYPE
;
4140 GNM_SOW_SPIN_BUTTON_TYPE
;
4141 GNM_SOW_SLIDER_TYPE
;