3 * sheet-object-widget.c: SheetObject wrappers for simple gtk widgets.
5 * Copyright (C) 2000-2006 Jody Goldberg (jody@gnome.org)
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
22 #include <gnumeric-config.h>
23 #include <glib/gi18n-lib.h>
25 #include <application.h>
26 #include <sheet-object-widget-impl.h>
27 #include <widgets/gnm-radiobutton.h>
29 #include <gnumeric-simple-canvas.h>
32 #include <dependent.h>
33 #include <sheet-control-gui.h>
34 #include <sheet-object-impl.h>
36 #include <parse-util.h>
39 #include <selection.h>
45 #include <widgets/gnm-expr-entry.h>
46 #include <dialogs/dialogs.h>
47 #include <dialogs/help.h>
50 #include <gnm-format.h>
51 #include <number-match.h>
53 #include <goffice/goffice.h>
55 #include <gsf/gsf-impl-utils.h>
56 #include <libxml/globals.h>
57 #include <gdk/gdkkeysyms.h>
61 #define CXML2C(s) ((char const *)(s))
62 #define CC2XML(s) ((xmlChar const *)(s))
64 static inline gboolean
65 attr_eq (const xmlChar
*a
, const char *s
)
67 return !strcmp (CXML2C (a
), s
);
70 /****************************************************************************/
73 cb_so_get_ref (GnmDependent
*dep
, G_GNUC_UNUSED SheetObject
*so
, gpointer user
)
75 GnmDependent
**pdep
= user
;
80 so_get_ref (SheetObject
const *so
, GnmCellRef
*res
, gboolean force_sheet
)
83 GnmDependent
*dep
= NULL
;
85 g_return_val_if_fail (so
!= NULL
, NULL
);
87 /* Let's hope there's just one. */
88 sheet_object_foreach_dep ((SheetObject
*)so
, cb_so_get_ref
, &dep
);
89 g_return_val_if_fail (dep
, NULL
);
91 if (dep
->texpr
== NULL
)
94 target
= gnm_expr_top_get_range (dep
->texpr
);
98 *res
= target
->v_range
.cell
.a
;
99 value_release (target
);
101 if (force_sheet
&& res
->sheet
== NULL
)
102 res
->sheet
= sheet_object_get_sheet (so
);
107 cb_so_clear_sheet (GnmDependent
*dep
, G_GNUC_UNUSED SheetObject
*so
, G_GNUC_UNUSED gpointer user
)
109 if (dependent_is_linked (dep
))
110 dependent_unlink (dep
);
115 so_clear_sheet (SheetObject
*so
)
117 /* Note: This implements sheet_object_clear_sheet. */
118 sheet_object_foreach_dep (so
, cb_so_clear_sheet
, NULL
);
123 get_goc_widget (SheetObjectView
*view
)
125 GocGroup
*group
= GOC_GROUP (view
);
127 if (group
== NULL
|| group
->children
== NULL
)
130 return GOC_WIDGET (group
->children
->data
);
134 so_widget_view_set_bounds (SheetObjectView
*sov
, double const *coords
, gboolean visible
)
136 GocItem
*view
= GOC_ITEM (sov
);
137 double scale
= goc_canvas_get_pixels_per_unit (view
->canvas
);
138 double left
= MIN (coords
[0], coords
[2]) / scale
;
139 double top
= MIN (coords
[1], coords
[3]) / scale
;
140 double width
= (fabs (coords
[2] - coords
[0]) + 1.) / scale
;
141 double height
= (fabs (coords
[3] - coords
[1]) + 1.) / scale
;
143 /* We only need the next check for frames, but it doesn't hurt otherwise. */
148 /* NOTE : far point is EXCLUDED so we add 1 */
149 goc_widget_set_bounds (get_goc_widget (sov
),
150 left
, top
, width
, height
);
151 goc_item_show (view
);
153 goc_item_hide (view
);
157 so_widget_view_get_window (GocItem
*item
)
159 GocGroup
*group
= GOC_GROUP (item
);
160 return goc_item_get_window (GOC_ITEM (group
->children
->data
));
164 so_widget_view_class_init (SheetObjectViewClass
*sov_klass
)
166 GocItemClass
*item_klass
= (GocItemClass
*) sov_klass
;
167 sov_klass
->set_bounds
= so_widget_view_set_bounds
;
168 item_klass
->get_window
= so_widget_view_get_window
;
171 static GSF_CLASS (SOWidgetView
, so_widget_view
,
172 so_widget_view_class_init
, NULL
,
175 /****************************************************************************/
177 #define SHEET_OBJECT_CONFIG_KEY "sheet-object-config-dialog"
179 #define GNM_SOW_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GNM_SOW_TYPE, SheetObjectWidgetClass))
180 #define SOW_CLASS(so) (GNM_SOW_CLASS (G_OBJECT_GET_CLASS(so)))
182 #define SOW_MAKE_TYPE(n1, n2, fn_config, fn_set_sheet, fn_clear_sheet, fn_foreach_dep, \
183 fn_copy, fn_write_sax, fn_prep_sax_parser, \
184 fn_get_property, fn_set_property, \
185 fn_draw_cairo, class_init_code) \
188 sheet_widget_ ## n1 ## _class_init (GObjectClass *object_class) \
190 SheetObjectWidgetClass *sow_class = GNM_SOW_CLASS (object_class); \
191 SheetObjectClass *so_class = GNM_SO_CLASS (object_class); \
192 object_class->finalize = &sheet_widget_ ## n1 ## _finalize; \
193 object_class->set_property = fn_set_property; \
194 object_class->get_property = fn_get_property; \
195 so_class->user_config = fn_config; \
196 so_class->interactive = TRUE; \
197 so_class->assign_to_sheet = fn_set_sheet; \
198 so_class->remove_from_sheet = fn_clear_sheet; \
199 so_class->foreach_dep = fn_foreach_dep; \
200 so_class->copy = fn_copy; \
201 so_class->write_xml_sax = fn_write_sax; \
202 so_class->prep_sax_parser = fn_prep_sax_parser; \
203 so_class->draw_cairo = fn_draw_cairo; \
204 sow_class->create_widget = &sheet_widget_ ## n1 ## _create_widget; \
205 { class_init_code; } \
208 GSF_CLASS (SheetWidget ## n2, sheet_widget_ ## n1, \
209 &sheet_widget_ ## n1 ## _class_init, \
210 &sheet_widget_ ## n1 ## _init, \
218 SheetObjectClass parent_class
;
219 GtkWidget
*(*create_widget
)(SheetObjectWidget
*);
220 } SheetObjectWidgetClass
;
222 static GObjectClass
*sheet_object_widget_class
= NULL
;
225 sow_create_widget (SheetObjectWidget
*sow
)
227 GtkWidget
*w
= SOW_CLASS(sow
)->create_widget (sow
);
228 GtkStyleContext
*context
= gtk_widget_get_style_context (w
);
229 gtk_style_context_add_class (context
, "sheet-object");
234 sheet_widget_draw_cairo (SheetObject
const *so
, cairo_t
*cr
,
235 double width
, double height
)
237 /* This is the default for so widgets without their own method */
238 /* See bugs #705638 and #705640 */
239 if (NULL
!= gdk_screen_get_default ()) {
240 GtkWidget
*win
= gtk_offscreen_window_new ();
241 GtkWidget
*w
= sow_create_widget (GNM_SOW (so
));
243 gtk_container_add (GTK_CONTAINER (win
), w
);
244 gtk_widget_set_size_request (w
, width
, height
);
245 gtk_widget_show_all (win
);
246 gtk_container_propagate_draw (GTK_CONTAINER (win
), w
, cr
);
247 gtk_widget_destroy (win
);
249 g_warning (_("Because of GTK bug #705640, a sheet object widget is not being printed."));
253 sax_write_dep (GsfXMLOut
*output
, GnmDependent
const *dep
, char const *id
,
254 GnmConventions
const *convs
)
256 if (dep
->texpr
!= NULL
) {
260 parse_pos_init_dep (&pos
, dep
);
261 val
= gnm_expr_top_as_string (dep
->texpr
, &pos
, convs
);
262 gsf_xml_out_add_cstr (output
, id
, val
);
268 sax_read_dep (xmlChar
const * const *attrs
, char const *name
,
269 GnmDependent
*dep
, GsfXMLIn
*xin
, GnmConventions
const *convs
)
271 g_return_val_if_fail (attrs
!= NULL
, FALSE
);
272 g_return_val_if_fail (attrs
[0] != NULL
, FALSE
);
273 g_return_val_if_fail (attrs
[1] != NULL
, FALSE
);
275 if (!attr_eq (attrs
[0], name
))
279 if (attrs
[1] != NULL
&& *attrs
[1] != '\0') {
282 parse_pos_init_sheet (&pp
, gnm_xml_in_cur_sheet (xin
));
283 dep
->texpr
= gnm_expr_parse_str (CXML2C (attrs
[1]), &pp
,
284 GNM_EXPR_PARSE_DEFAULT
,
292 static SheetObjectView
*
293 sheet_object_widget_new_view (SheetObject
*so
, SheetObjectViewContainer
*container
)
295 GtkWidget
*view_widget
= sow_create_widget (GNM_SOW (so
));
296 GocItem
*view_item
= goc_item_new (
297 gnm_pane_object_group (GNM_PANE (container
)),
298 so_widget_view_get_type (),
300 goc_item_new (GOC_GROUP (view_item
),
302 "widget", view_widget
,
304 /* g_warning ("%p is widget for so %p", (void *)view_widget, (void *)so);*/
305 gtk_widget_show_all (view_widget
);
306 goc_item_hide (view_item
);
307 gnm_pane_widget_register (so
, view_widget
, view_item
);
308 return gnm_pane_object_register (so
, view_item
, TRUE
);
312 sheet_object_widget_class_init (GObjectClass
*object_class
)
314 SheetObjectClass
*so_class
= GNM_SO_CLASS (object_class
);
315 SheetObjectWidgetClass
*sow_class
= GNM_SOW_CLASS (object_class
);
317 sheet_object_widget_class
= G_OBJECT_CLASS (object_class
);
319 /* SheetObject class method overrides */
320 so_class
->new_view
= sheet_object_widget_new_view
;
321 so_class
->rubber_band_directly
= TRUE
;
322 so_class
->draw_cairo
= sheet_widget_draw_cairo
;
324 sow_class
->create_widget
= NULL
;
328 sheet_object_widget_init (SheetObjectWidget
*sow
)
330 SheetObject
*so
= GNM_SO (sow
);
331 so
->flags
|= SHEET_OBJECT_CAN_PRESS
;
334 GSF_CLASS (SheetObjectWidget
, sheet_object_widget
,
335 sheet_object_widget_class_init
,
336 sheet_object_widget_init
,
339 static WorkbookControl
*
340 widget_wbc (GtkWidget
*widget
)
342 return scg_wbc (GNM_SIMPLE_CANVAS (gtk_widget_get_ancestor (widget
, GNM_SIMPLE_CANVAS_TYPE
))->scg
);
346 /****************************************************************************/
347 #define GNM_SOW_FRAME(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNM_SOW_FRAME_TYPE, SheetWidgetFrame))
349 SheetObjectWidget sow
;
352 typedef SheetObjectWidgetClass SheetWidgetFrameClass
;
360 sheet_widget_frame_get_property (GObject
*obj
, guint param_id
,
361 GValue
*value
, GParamSpec
*pspec
)
363 SheetWidgetFrame
*swf
= GNM_SOW_FRAME (obj
);
367 g_value_set_string (value
, swf
->label
);
370 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj
, param_id
, pspec
);
376 sheet_widget_frame_set_property (GObject
*obj
, guint param_id
,
377 GValue
const *value
, GParamSpec
*pspec
)
379 SheetWidgetFrame
*swf
= GNM_SOW_FRAME (obj
);
383 sheet_widget_frame_set_label (GNM_SO (swf
),
384 g_value_get_string (value
));
387 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj
, param_id
, pspec
);
394 sheet_widget_frame_init_full (SheetWidgetFrame
*swf
, char const *text
)
396 swf
->label
= g_strdup (text
);
400 sheet_widget_frame_init (SheetWidgetFrame
*swf
)
402 sheet_widget_frame_init_full (swf
, _("Frame"));
406 sheet_widget_frame_finalize (GObject
*obj
)
408 SheetWidgetFrame
*swf
= GNM_SOW_FRAME (obj
);
413 sheet_object_widget_class
->finalize (obj
);
417 sheet_widget_frame_create_widget (SheetObjectWidget
*sow
)
419 GtkWidget
*widget
= gtk_event_box_new (),
420 *frame
= gtk_frame_new (GNM_SOW_FRAME (sow
)->label
);
421 gtk_container_add (GTK_CONTAINER (widget
), frame
);
422 gtk_event_box_set_visible_window (GTK_EVENT_BOX (widget
), FALSE
);
427 sheet_widget_frame_copy (SheetObject
*dst
, SheetObject
const *src
)
429 sheet_widget_frame_init_full (GNM_SOW_FRAME (dst
),
430 GNM_SOW_FRAME (src
)->label
);
434 sheet_widget_frame_write_xml_sax (SheetObject
const *so
, GsfXMLOut
*output
,
435 G_GNUC_UNUSED GnmConventions
const *convs
)
437 SheetWidgetFrame
const *swf
= GNM_SOW_FRAME (so
);
438 gsf_xml_out_add_cstr (output
, "Label", swf
->label
);
442 sheet_widget_frame_prep_sax_parser (SheetObject
*so
, G_GNUC_UNUSED GsfXMLIn
*xin
,
443 xmlChar
const **attrs
,
444 G_GNUC_UNUSED GnmConventions
const *convs
)
446 SheetWidgetFrame
*swf
= GNM_SOW_FRAME (so
);
447 for (; attrs
!= NULL
&& attrs
[0] && attrs
[1] ; attrs
+= 2)
448 if (attr_eq (attrs
[0], "Label")) {
450 swf
->label
= g_strdup (CXML2C (attrs
[1]));
459 GtkWidget
*old_focus
;
462 SheetWidgetFrame
*swf
;
467 cb_frame_config_destroy (FrameConfigState
*state
)
469 g_return_if_fail (state
!= NULL
);
471 g_free (state
->old_label
);
472 state
->old_label
= NULL
;
473 state
->dialog
= NULL
;
478 cb_frame_config_ok_clicked (G_GNUC_UNUSED GtkWidget
*button
, FrameConfigState
*state
)
480 gchar
const *text
= gtk_entry_get_text(GTK_ENTRY(state
->label
));
482 cmd_so_set_frame_label (GNM_WBC (state
->wbcg
),
484 g_strdup (state
->old_label
), g_strdup (text
));
485 gtk_widget_destroy (state
->dialog
);
489 sheet_widget_frame_set_label (SheetObject
*so
, char const* str
)
491 SheetWidgetFrame
*swf
= GNM_SOW_FRAME (so
);
494 str
= str
? str
: "";
496 if (go_str_compare (str
, swf
->label
) == 0)
500 swf
->label
= g_strdup (str
);
502 for (ptr
= swf
->sow
.so
.realized_list
; ptr
!= NULL
; ptr
= ptr
->next
) {
503 SheetObjectView
*view
= ptr
->data
;
504 GocWidget
*item
= get_goc_widget (view
);
505 GList
*children
= gtk_container_get_children (GTK_CONTAINER (item
->widget
));
506 gtk_frame_set_label (GTK_FRAME (children
->data
), str
);
507 g_list_free (children
);
512 cb_frame_config_cancel_clicked (G_GNUC_UNUSED GtkWidget
*button
, FrameConfigState
*state
)
514 sheet_widget_frame_set_label (GNM_SO (state
->swf
), state
->old_label
);
516 gtk_widget_destroy (state
->dialog
);
520 cb_frame_label_changed (GtkWidget
*entry
, FrameConfigState
*state
)
524 text
= gtk_entry_get_text(GTK_ENTRY(entry
));
525 sheet_widget_frame_set_label (GNM_SO (state
->swf
), text
);
529 sheet_widget_frame_user_config (SheetObject
*so
, SheetControl
*sc
)
531 SheetWidgetFrame
*swf
= GNM_SOW_FRAME (so
);
532 WBCGtk
*wbcg
= scg_wbcg (GNM_SCG (sc
));
533 FrameConfigState
*state
;
536 g_return_if_fail (swf
!= NULL
);
538 /* Only pop up one copy per workbook */
539 if (gnm_dialog_raise_if_exists (wbcg
, SHEET_OBJECT_CONFIG_KEY
))
542 gui
= gnm_gtk_builder_load ("res:ui/so-frame.ui", NULL
, GO_CMD_CONTEXT (wbcg
));
545 state
= g_new (FrameConfigState
, 1);
548 state
->sheet
= sc_sheet (sc
);
549 state
->old_focus
= NULL
;
550 state
->old_label
= g_strdup(swf
->label
);
551 state
->dialog
= go_gtk_builder_get_widget (gui
, "so_frame");
553 state
->label
= go_gtk_builder_get_widget (gui
, "entry");
554 gtk_entry_set_text (GTK_ENTRY(state
->label
), swf
->label
);
555 gtk_editable_select_region (GTK_EDITABLE(state
->label
), 0, -1);
556 gnm_editable_enters (GTK_WINDOW (state
->dialog
),
557 GTK_WIDGET (state
->label
));
559 g_signal_connect (G_OBJECT(state
->label
),
561 G_CALLBACK (cb_frame_label_changed
), state
);
562 g_signal_connect (G_OBJECT (go_gtk_builder_get_widget (gui
,
565 G_CALLBACK (cb_frame_config_ok_clicked
), state
);
566 g_signal_connect (G_OBJECT (go_gtk_builder_get_widget (gui
,
569 G_CALLBACK (cb_frame_config_cancel_clicked
), state
);
571 gnm_init_help_button (
572 go_gtk_builder_get_widget (gui
, "help_button"),
573 GNUMERIC_HELP_LINK_SO_FRAME
);
576 gnm_keyed_dialog (state
->wbcg
, GTK_WINDOW (state
->dialog
),
577 SHEET_OBJECT_CONFIG_KEY
);
579 wbc_gtk_attach_guru (state
->wbcg
, state
->dialog
);
580 g_object_set_data_full (G_OBJECT (state
->dialog
),
581 "state", state
, (GDestroyNotify
) cb_frame_config_destroy
);
582 g_object_unref (gui
);
584 gtk_widget_show (state
->dialog
);
587 static PangoFontDescription
*
590 // Note: Under gnumeric, we get a proper font using GtkStyleContext.
591 // Under ssconvert, we try GSettings.
592 // The 'sans 10' is just insurance
594 PangoFontDescription
*desc
;
598 if (gdk_screen_get_default ()) {
599 // Without a default screen, the following will crash
601 GtkStyleContext
*style
= gtk_style_context_new ();
602 GtkWidgetPath
*path
= gtk_widget_path_new ();
604 gtk_style_context_set_path (style
, path
);
605 gtk_widget_path_unref (path
);
607 gtk_style_context_get (style
, GTK_STATE_FLAG_NORMAL
,
608 GTK_STYLE_PROPERTY_FONT
, &desc
, NULL
);
609 g_object_unref (style
);
611 desc
= pango_font_description_new ();
613 mask
= pango_font_description_get_set_fields (desc
);
614 if ((mask
& PANGO_FONT_MASK_SIZE
) != 0)
615 size
= pango_font_description_get_size (desc
);
617 if (gnm_debug_flag ("so-font")) {
618 char *s
= pango_font_description_to_string (desc
);
619 g_printerr ("from GtkStyleContext font=\"%s\", family set = %i,"
620 " size set = %i, size = %i\n",
621 s
, ((mask
& PANGO_FONT_MASK_FAMILY
) != 0),
622 ((mask
& PANGO_FONT_MASK_SIZE
) != 0), size
);
626 if ((mask
& PANGO_FONT_MASK_FAMILY
) == 0 || size
== 0) {
627 /* Trying gsettings */
628 GSettings
*set
= g_settings_new ("org.gnome.desktop.interface");
629 char *font_name
= g_settings_get_string (set
, "font-name");
630 if (font_name
!= NULL
) {
631 pango_font_description_free (desc
);
632 desc
= pango_font_description_from_string (font_name
);
634 mask
= pango_font_description_get_set_fields (desc
);
635 if ((mask
& PANGO_FONT_MASK_SIZE
) != 0)
636 size
= pango_font_description_get_size (desc
);
639 if (gnm_debug_flag ("so-font")) {
640 char *s
= pango_font_description_to_string (desc
);
641 g_printerr ("from GSettings: font=\"%s\", family set = %i,"
642 " size set = %i, size = %i\n",
643 s
, ((mask
& PANGO_FONT_MASK_FAMILY
) != 0),
644 ((mask
& PANGO_FONT_MASK_SIZE
) != 0), size
);
650 if ((mask
& PANGO_FONT_MASK_FAMILY
) == 0 || size
== 0) {
651 pango_font_description_free (desc
);
652 desc
= pango_font_description_from_string ("sans 10");
653 if (gnm_debug_flag ("so-font"))
654 g_printerr ("Using \"sans 10\" instead.\n");
661 draw_cairo_text (cairo_t
*cr
, char const *text
, int *pwidth
, int *pheight
,
662 gboolean centered_v
, gboolean centered_h
, gboolean single
, gint highlight_n
, gboolean scale
)
664 PangoLayout
*layout
= pango_cairo_create_layout (cr
);
665 double const scale_h
= 72. / gnm_app_display_dpi_get (TRUE
);
666 double const scale_v
= 72. / gnm_app_display_dpi_get (FALSE
);
667 PangoFontDescription
*desc
= get_font ();
670 pango_context_set_font_description
671 (pango_layout_get_context (layout
), desc
);
672 pango_layout_set_spacing (layout
, 3 * PANGO_SCALE
);
673 pango_layout_set_single_paragraph_mode (layout
, single
);
674 pango_layout_set_text (layout
, text
, -1);
675 pango_layout_get_pixel_size (layout
, &width
, &height
);
677 cairo_scale (cr
, scale_h
, scale_v
);
679 if (scale
&& pwidth
!= NULL
&& pheight
!= NULL
) {
680 double sc_x
= ((double) *pwidth
)/(width
* scale_h
);
681 double sc_y
= ((double) *pheight
)/(height
* scale_v
);
682 double sc
= MIN(sc_x
, sc_y
);
685 cairo_scale (cr
, sc
, sc
);
689 cairo_rel_move_to (cr
, 0., 0.5 - ((double)height
)/2.);
691 cairo_rel_move_to (cr
, 0.5 - ((double)width
)/2., 0.);
692 if (highlight_n
> 0 && pheight
!= NULL
&& pwidth
!= NULL
) {
693 PangoLayoutIter
*pliter
;
694 gboolean got_line
= TRUE
;
696 pliter
= pango_layout_get_iter (layout
);
697 for (i
= 1; i
< highlight_n
; i
++)
698 got_line
= pango_layout_iter_next_line (pliter
);
702 double dy0
= 0, dy1
= 0;
703 pango_layout_iter_get_line_yrange (pliter
, &y0
, &y1
);
704 dy0
= y0
/ (double)PANGO_SCALE
;
705 dy1
= y1
/ (double)PANGO_SCALE
;
707 if (dy1
> (*pheight
- 4)/scale_v
)
708 cairo_translate (cr
, 0, (*pheight
- 4)/scale_v
- dy1
);
711 cairo_rectangle (cr
, -4/scale_h
, dy0
,
712 *pwidth
/scale_h
, dy1
- dy0
);
713 cairo_set_source_rgb(cr
, 0.8, 0.8, 0.8);
716 pango_layout_iter_free (pliter
);
717 cairo_set_source_rgb(cr
, 0, 0, 0);
719 pango_cairo_show_layout (cr
, layout
);
720 pango_font_description_free (desc
);
721 g_object_unref (layout
);
724 *pwidth
= width
* scale_h
;
726 *pheight
= height
* scale_v
;
730 sheet_widget_frame_draw_cairo (SheetObject
const *so
, cairo_t
*cr
,
731 double width
, double height
)
733 SheetWidgetFrame
*swf
= GNM_SOW_FRAME (so
);
735 int theight
= 0, twidth
= 0;
737 cairo_move_to (cr
, 10, 0);
740 cairo_set_source_rgb(cr
, 0.0, 0.0, 0.0);
741 draw_cairo_text (cr
, swf
->label
, &twidth
, &theight
, FALSE
, FALSE
, TRUE
, 0, FALSE
);
744 cairo_set_line_width (cr
, 1);
745 cairo_set_line_cap (cr
, CAIRO_LINE_CAP_ROUND
);
746 cairo_set_source_rgb(cr
, 0.5, 0.5, 0.5);
748 cairo_move_to (cr
, 6, theight
/2);
749 cairo_line_to (cr
, 0, theight
/2);
750 cairo_line_to (cr
, 0, height
);
751 cairo_line_to (cr
, width
, height
);
752 cairo_line_to (cr
, width
, theight
/2);
753 cairo_line_to (cr
, 14 + twidth
, theight
/2);
756 cairo_set_source_rgb(cr
, 0.8, 0.8, 0.8);
758 cairo_move_to (cr
, 6, theight
/2 + 1);
759 cairo_line_to (cr
, 1, theight
/2 + 1);
760 cairo_line_to (cr
, 1, height
- 1);
761 cairo_line_to (cr
, width
- 1, height
- 1);
762 cairo_line_to (cr
, width
- 1, theight
/2 + 1);
763 cairo_line_to (cr
, 14 + twidth
, theight
/2 + 1);
770 SOW_MAKE_TYPE (frame
, Frame
,
771 sheet_widget_frame_user_config
,
775 sheet_widget_frame_copy
,
776 sheet_widget_frame_write_xml_sax
,
777 sheet_widget_frame_prep_sax_parser
,
778 sheet_widget_frame_get_property
,
779 sheet_widget_frame_set_property
,
780 sheet_widget_frame_draw_cairo
,
782 g_object_class_install_property
783 (object_class
, SOF_PROP_TEXT
,
784 g_param_spec_string ("text", NULL
, NULL
, NULL
,
785 GSF_PARAM_STATIC
| G_PARAM_READWRITE
));
788 /****************************************************************************/
789 #define GNM_SOW_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNM_SOW_BUTTON_TYPE, SheetWidgetButton))
790 #define DEP_TO_BUTTON(d_ptr) (SheetWidgetButton *)(((char *)d_ptr) - G_STRUCT_OFFSET(SheetWidgetButton, dep))
792 SheetObjectWidget sow
;
796 PangoAttrList
*markup
;
799 typedef SheetObjectWidgetClass SheetWidgetButtonClass
;
808 sheet_widget_button_get_property (GObject
*obj
, guint param_id
,
809 GValue
*value
, GParamSpec
*pspec
)
811 SheetWidgetButton
*swb
= GNM_SOW_BUTTON (obj
);
815 g_value_set_string (value
, swb
->label
);
817 case SOB_PROP_MARKUP
:
818 g_value_set_boxed (value
, NULL
); /* swb->markup */
821 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj
, param_id
, pspec
);
827 sheet_widget_button_set_property (GObject
*obj
, guint param_id
,
828 GValue
const *value
, GParamSpec
*pspec
)
830 SheetWidgetButton
*swb
= GNM_SOW_BUTTON (obj
);
834 sheet_widget_button_set_label (GNM_SO (swb
),
835 g_value_get_string (value
));
837 case SOB_PROP_MARKUP
:
839 sheet_widget_button_set_markup (GNM_SO (swb
),
840 g_value_peek_pointer (value
));
844 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj
, param_id
, pspec
);
850 button_eval (GnmDependent
*dep
)
854 gboolean err
, result
;
856 v
= gnm_expr_top_eval (dep
->texpr
, eval_pos_init_dep (&pos
, dep
),
857 GNM_EXPR_EVAL_SCALAR_NON_EMPTY
);
858 result
= value_get_as_bool (v
, &err
);
861 SheetWidgetButton
*swb
= DEP_TO_BUTTON(dep
);
868 button_debug_name (GnmDependent
const *dep
, GString
*target
)
870 g_string_append_printf (target
, "Button%p", (void *)dep
);
873 static DEPENDENT_MAKE_TYPE (button
, NULL
)
876 sheet_widget_button_init_full (SheetWidgetButton
*swb
,
877 GnmCellRef
const *ref
,
879 PangoAttrList
*markup
)
881 SheetObject
*so
= GNM_SO (swb
);
883 so
->flags
&= ~SHEET_OBJECT_PRINT
;
884 swb
->label
= g_strdup (text
);
885 swb
->markup
= markup
;
887 swb
->dep
.sheet
= NULL
;
888 swb
->dep
.flags
= button_get_dep_type ();
889 swb
->dep
.texpr
= (ref
!= NULL
)
890 ? gnm_expr_top_new (gnm_expr_new_cellref (ref
))
892 if (markup
) pango_attr_list_ref (markup
);
896 sheet_widget_button_init (SheetWidgetButton
*swb
)
898 sheet_widget_button_init_full (swb
, NULL
, _("Button"), NULL
);
902 sheet_widget_button_finalize (GObject
*obj
)
904 SheetWidgetButton
*swb
= GNM_SOW_BUTTON (obj
);
910 pango_attr_list_unref (swb
->markup
);
914 dependent_set_expr (&swb
->dep
, NULL
);
916 sheet_object_widget_class
->finalize (obj
);
920 cb_button_pressed (GtkToggleButton
*button
, SheetWidgetButton
*swb
)
926 if (so_get_ref (GNM_SO (swb
), &ref
, TRUE
) != NULL
) {
927 cmd_so_set_value (widget_wbc (GTK_WIDGET (button
)),
929 &ref
, value_new_bool (TRUE
),
930 sheet_object_get_sheet (GNM_SO (swb
)));
935 cb_button_released (GtkToggleButton
*button
, SheetWidgetButton
*swb
)
941 if (so_get_ref (GNM_SO (swb
), &ref
, TRUE
) != NULL
) {
942 cmd_so_set_value (widget_wbc (GTK_WIDGET (button
)),
943 _("Released Button"),
944 &ref
, value_new_bool (FALSE
),
945 sheet_object_get_sheet (GNM_SO (swb
)));
950 sheet_widget_button_create_widget (SheetObjectWidget
*sow
)
952 SheetWidgetButton
*swb
= GNM_SOW_BUTTON (sow
);
953 GtkWidget
*w
= gtk_button_new_with_label (swb
->label
);
954 gtk_widget_set_can_focus (w
, FALSE
);
955 gtk_label_set_attributes (GTK_LABEL (gtk_bin_get_child (GTK_BIN (w
))),
957 g_signal_connect (G_OBJECT (w
),
959 G_CALLBACK (cb_button_pressed
), swb
);
960 g_signal_connect (G_OBJECT (w
),
962 G_CALLBACK (cb_button_released
), swb
);
967 sheet_widget_button_copy (SheetObject
*dst
, SheetObject
const *src
)
969 SheetWidgetButton
const *src_swb
= GNM_SOW_BUTTON (src
);
970 SheetWidgetButton
*dst_swb
= GNM_SOW_BUTTON (dst
);
972 sheet_widget_button_init_full (dst_swb
,
973 so_get_ref (src
, &ref
, FALSE
),
976 dst_swb
->value
= src_swb
->value
;
981 GnmExprEntry
*expression
;
985 GtkWidget
*old_focus
;
988 SheetWidgetButton
*swb
;
993 cb_button_set_focus (G_GNUC_UNUSED GtkWidget
*window
, GtkWidget
*focus_widget
,
994 ButtonConfigState
*state
)
996 /* Note: half of the set-focus action is handle by the default
997 * callback installed by wbc_gtk_attach_guru */
999 /* Force an update of the content in case it needs tweaking (eg make it
1001 if (state
->old_focus
!= NULL
&&
1002 GNM_EXPR_ENTRY_IS (gtk_widget_get_parent (state
->old_focus
))) {
1004 GnmExprTop
const *texpr
= gnm_expr_entry_parse
1005 (GNM_EXPR_ENTRY (gtk_widget_get_parent (state
->old_focus
)),
1006 parse_pos_init_sheet (&pp
, state
->sheet
),
1007 NULL
, FALSE
, GNM_EXPR_PARSE_DEFAULT
);
1009 gnm_expr_top_unref (texpr
);
1011 state
->old_focus
= focus_widget
;
1015 cb_button_config_destroy (ButtonConfigState
*state
)
1017 g_return_if_fail (state
!= NULL
);
1019 g_free (state
->old_label
);
1020 state
->old_label
= NULL
;
1021 state
->dialog
= NULL
;
1026 cb_button_config_ok_clicked (G_GNUC_UNUSED GtkWidget
*button
, ButtonConfigState
*state
)
1028 SheetObject
*so
= GNM_SO (state
->swb
);
1030 GnmExprTop
const *texpr
= gnm_expr_entry_parse (state
->expression
,
1031 parse_pos_init_sheet (&pp
, so
->sheet
),
1032 NULL
, FALSE
, GNM_EXPR_PARSE_DEFAULT
);
1033 gchar
const *text
= gtk_entry_get_text(GTK_ENTRY(state
->label
));
1035 cmd_so_set_button (GNM_WBC (state
->wbcg
), so
,
1036 texpr
, g_strdup (state
->old_label
), g_strdup (text
));
1038 gtk_widget_destroy (state
->dialog
);
1042 cb_button_config_cancel_clicked (G_GNUC_UNUSED GtkWidget
*button
, ButtonConfigState
*state
)
1044 sheet_widget_button_set_label (GNM_SO (state
->swb
),
1046 gtk_widget_destroy (state
->dialog
);
1050 cb_button_label_changed (GtkEntry
*entry
, ButtonConfigState
*state
)
1052 sheet_widget_button_set_label (GNM_SO (state
->swb
),
1053 gtk_entry_get_text (entry
));
1057 sheet_widget_button_user_config (SheetObject
*so
, SheetControl
*sc
)
1059 SheetWidgetButton
*swb
= GNM_SOW_BUTTON (so
);
1060 WBCGtk
*wbcg
= scg_wbcg (GNM_SCG (sc
));
1061 ButtonConfigState
*state
;
1065 g_return_if_fail (swb
!= NULL
);
1067 /* Only pop up one copy per workbook */
1068 if (gnm_dialog_raise_if_exists (wbcg
, SHEET_OBJECT_CONFIG_KEY
))
1071 gui
= gnm_gtk_builder_load ("res:ui/so-button.ui", NULL
, GO_CMD_CONTEXT (wbcg
));
1074 state
= g_new (ButtonConfigState
, 1);
1077 state
->sheet
= sc_sheet (sc
);
1078 state
->old_focus
= NULL
;
1079 state
->old_label
= g_strdup (swb
->label
);
1080 state
->dialog
= go_gtk_builder_get_widget (gui
, "SO-Button");
1082 grid
= go_gtk_builder_get_widget (gui
, "main-grid");
1084 state
->expression
= gnm_expr_entry_new (wbcg
, TRUE
);
1085 gnm_expr_entry_set_flags (state
->expression
,
1086 GNM_EE_FORCE_ABS_REF
| GNM_EE_SHEET_OPTIONAL
| GNM_EE_SINGLE_RANGE
,
1088 gnm_expr_entry_load_from_dep (state
->expression
, &swb
->dep
);
1089 go_atk_setup_label (go_gtk_builder_get_widget (gui
, "label_linkto"),
1090 GTK_WIDGET (state
->expression
));
1091 gtk_grid_attach (GTK_GRID (grid
),
1092 GTK_WIDGET (state
->expression
), 1, 0, 1, 1);
1093 gtk_widget_show (GTK_WIDGET (state
->expression
));
1095 state
->label
= go_gtk_builder_get_widget (gui
, "label_entry");
1096 gtk_entry_set_text (GTK_ENTRY (state
->label
), swb
->label
);
1097 gtk_editable_select_region (GTK_EDITABLE(state
->label
), 0, -1);
1098 gnm_editable_enters (GTK_WINDOW (state
->dialog
),
1099 GTK_WIDGET (state
->expression
));
1100 gnm_editable_enters (GTK_WINDOW (state
->dialog
),
1101 GTK_WIDGET (state
->label
));
1103 g_signal_connect (G_OBJECT (state
->label
),
1105 G_CALLBACK (cb_button_label_changed
), state
);
1106 g_signal_connect (G_OBJECT (go_gtk_builder_get_widget (gui
, "ok_button")),
1108 G_CALLBACK (cb_button_config_ok_clicked
), state
);
1109 g_signal_connect (G_OBJECT (go_gtk_builder_get_widget (gui
, "cancel_button")),
1111 G_CALLBACK (cb_button_config_cancel_clicked
), state
);
1113 gnm_init_help_button (
1114 go_gtk_builder_get_widget (gui
, "help_button"),
1115 GNUMERIC_HELP_LINK_SO_BUTTON
);
1117 gnm_keyed_dialog (state
->wbcg
, GTK_WINDOW (state
->dialog
),
1118 SHEET_OBJECT_CONFIG_KEY
);
1120 wbc_gtk_attach_guru (state
->wbcg
, state
->dialog
);
1121 g_object_set_data_full (G_OBJECT (state
->dialog
),
1122 "state", state
, (GDestroyNotify
) cb_button_config_destroy
);
1124 /* Note: half of the set-focus action is handle by the default */
1125 /* callback installed by wbc_gtk_attach_guru */
1126 g_signal_connect (G_OBJECT (state
->dialog
), "set-focus",
1127 G_CALLBACK (cb_button_set_focus
), state
);
1128 g_object_unref (gui
);
1130 gtk_widget_show (state
->dialog
);
1134 sheet_widget_button_set_sheet (SheetObject
*so
, Sheet
*sheet
)
1136 SheetWidgetButton
*swb
= GNM_SOW_BUTTON (so
);
1138 dependent_set_sheet (&swb
->dep
, sheet
);
1144 sheet_widget_button_foreach_dep (SheetObject
*so
,
1145 SheetObjectForeachDepFunc func
,
1148 SheetWidgetButton
*swb
= GNM_SOW_BUTTON (so
);
1149 func (&swb
->dep
, so
, user
);
1153 sheet_widget_button_write_xml_sax (SheetObject
const *so
, GsfXMLOut
*output
,
1154 GnmConventions
const *convs
)
1157 SheetWidgetButton
*swb
= GNM_SOW_BUTTON (so
);
1158 gsf_xml_out_add_cstr (output
, "Label", swb
->label
);
1159 gsf_xml_out_add_int (output
, "Value", swb
->value
);
1160 sax_write_dep (output
, &swb
->dep
, "Input", convs
);
1164 sheet_widget_button_prep_sax_parser (SheetObject
*so
, GsfXMLIn
*xin
,
1165 xmlChar
const **attrs
,
1166 GnmConventions
const *convs
)
1168 SheetWidgetButton
*swb
= GNM_SOW_BUTTON (so
);
1169 for (; attrs
!= NULL
&& attrs
[0] && attrs
[1] ; attrs
+= 2)
1170 if (attr_eq (attrs
[0], "Label"))
1171 g_object_set (G_OBJECT (swb
), "text", attrs
[1], NULL
);
1172 else if (gnm_xml_attr_int (attrs
, "Value", &swb
->value
))
1174 else if (sax_read_dep (attrs
, "Input", &swb
->dep
, xin
, convs
))
1179 sheet_widget_button_set_link (SheetObject
*so
, GnmExprTop
const *texpr
)
1181 SheetWidgetButton
*swb
= GNM_SOW_BUTTON (so
);
1182 dependent_set_expr (&swb
->dep
, texpr
);
1183 if (texpr
&& swb
->dep
.sheet
)
1184 dependent_link (&swb
->dep
);
1188 sheet_widget_button_get_link (SheetObject
*so
)
1190 SheetWidgetButton
*swb
= GNM_SOW_BUTTON (so
);
1191 GnmExprTop
const *texpr
= swb
->dep
.texpr
;
1194 gnm_expr_top_ref (texpr
);
1201 sheet_widget_button_set_label (SheetObject
*so
, char const *str
)
1204 SheetWidgetButton
*swb
= GNM_SOW_BUTTON (so
);
1207 if (go_str_compare (str
, swb
->label
) == 0)
1210 new_label
= g_strdup (str
);
1211 g_free (swb
->label
);
1212 swb
->label
= new_label
;
1214 for (ptr
= swb
->sow
.so
.realized_list
; ptr
!= NULL
; ptr
= ptr
->next
) {
1215 SheetObjectView
*view
= ptr
->data
;
1216 GocWidget
*item
= get_goc_widget (view
);
1217 gtk_button_set_label (GTK_BUTTON (item
->widget
), swb
->label
);
1222 sheet_widget_button_set_markup (SheetObject
*so
, PangoAttrList
*markup
)
1225 SheetWidgetButton
*swb
= GNM_SOW_BUTTON (so
);
1227 if (markup
== swb
->markup
)
1230 if (swb
->markup
) pango_attr_list_unref (swb
->markup
);
1231 swb
->markup
= markup
;
1232 if (markup
) pango_attr_list_ref (markup
);
1234 for (ptr
= swb
->sow
.so
.realized_list
; ptr
!= NULL
; ptr
= ptr
->next
) {
1235 SheetObjectView
*view
= ptr
->data
;
1236 GocWidget
*item
= get_goc_widget (view
);
1238 GTK_LABEL (gtk_bin_get_child (GTK_BIN (item
->widget
)));
1239 gtk_label_set_attributes (lab
, swb
->markup
);
1244 sheet_widget_button_draw_cairo (SheetObject
const *so
, cairo_t
*cr
,
1245 double width
, double height
)
1247 SheetWidgetButton
*swb
= GNM_SOW_BUTTON (so
);
1248 int twidth
, theight
;
1252 if (height
< 3 * radius
)
1253 radius
= height
/ 3.;
1254 if (width
< 3 * radius
)
1255 radius
= width
/ 3.;
1258 half_line
= radius
* 0.15;
1261 cairo_set_line_width (cr
, 2 * half_line
);
1262 cairo_set_source_rgb(cr
, 0.5, 0.5, 0.5);
1264 cairo_new_path (cr
);
1265 cairo_arc (cr
, radius
+ half_line
, radius
+ half_line
, radius
, M_PI
, - M_PI
/2);
1266 cairo_arc (cr
, width
- (radius
+ half_line
), radius
+ half_line
,
1267 radius
, - M_PI
/2, 0);
1268 cairo_arc (cr
, width
- (radius
+ half_line
), height
- (radius
+ half_line
),
1270 cairo_arc (cr
, (radius
+ half_line
), height
- (radius
+ half_line
),
1271 radius
, M_PI
/2, M_PI
);
1272 cairo_close_path (cr
);
1275 cairo_set_source_rgb(cr
, 0, 0, 0);
1277 cairo_move_to (cr
, width
/2., height
/2.);
1279 twidth
= 0.8 * width
;
1280 theight
= 0.8 * height
;
1281 draw_cairo_text (cr
, swb
->label
, &twidth
, &theight
, TRUE
, TRUE
, TRUE
, 0, TRUE
);
1283 cairo_new_path (cr
);
1287 SOW_MAKE_TYPE (button
, Button
,
1288 sheet_widget_button_user_config
,
1289 sheet_widget_button_set_sheet
,
1291 sheet_widget_button_foreach_dep
,
1292 sheet_widget_button_copy
,
1293 sheet_widget_button_write_xml_sax
,
1294 sheet_widget_button_prep_sax_parser
,
1295 sheet_widget_button_get_property
,
1296 sheet_widget_button_set_property
,
1297 sheet_widget_button_draw_cairo
,
1299 g_object_class_install_property
1300 (object_class
, SOB_PROP_TEXT
,
1301 g_param_spec_string ("text", NULL
, NULL
, NULL
,
1302 GSF_PARAM_STATIC
| G_PARAM_READWRITE
));
1303 g_object_class_install_property
1304 (object_class
, SOB_PROP_MARKUP
,
1305 g_param_spec_boxed ("markup", NULL
, NULL
, PANGO_TYPE_ATTR_LIST
,
1306 GSF_PARAM_STATIC
| G_PARAM_READWRITE
));
1309 /****************************************************************************/
1311 #define DEP_TO_ADJUSTMENT(d_ptr) (SheetWidgetAdjustment *)(((char *)d_ptr) - G_STRUCT_OFFSET(SheetWidgetAdjustment, dep))
1312 #define GNM_SOW_ADJUSTMENT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GNM_SOW_ADJUSTMENT_TYPE, SheetWidgetAdjustmentClass))
1313 #define SWA_CLASS(so) (GNM_SOW_ADJUSTMENT_CLASS (G_OBJECT_GET_CLASS(so)))
1316 SheetObjectWidget sow
;
1318 gboolean being_updated
;
1320 GtkAdjustment
*adjustment
;
1322 gboolean horizontal
;
1323 } SheetWidgetAdjustment
;
1326 SheetObjectWidgetClass parent_class
;
1328 gboolean has_orientation
;
1329 } SheetWidgetAdjustmentClass
;
1336 #ifndef g_signal_handlers_disconnect_by_data
1337 #define g_signal_handlers_disconnect_by_data(instance, data) \
1338 g_signal_handlers_disconnect_matched ((instance), G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, (data))
1341 cb_range_destroyed (GtkWidget
*w
, SheetWidgetAdjustment
*swa
)
1343 GObject
*accessible
= G_OBJECT (gtk_widget_get_accessible (w
));
1345 g_signal_handlers_disconnect_by_data (swa
->adjustment
, accessible
);
1349 sheet_widget_adjustment_set_value (SheetWidgetAdjustment
*swa
, double new_val
)
1351 if (swa
->being_updated
)
1353 swa
->being_updated
= TRUE
;
1354 gtk_adjustment_set_value (swa
->adjustment
, new_val
);
1355 swa
->being_updated
= FALSE
;
1359 * sheet_widget_adjustment_get_adjustment:
1362 * Returns: (transfer none): the associated #GtkAdjustment.
1365 sheet_widget_adjustment_get_adjustment (SheetObject
*so
)
1367 g_return_val_if_fail (GNM_IS_SOW_ADJUSTMENT (so
), NULL
);
1368 return (GNM_SOW_ADJUSTMENT (so
)->adjustment
);
1372 sheet_widget_adjustment_get_horizontal (SheetObject
*so
)
1374 g_return_val_if_fail (GNM_IS_SOW_ADJUSTMENT (so
), TRUE
);
1375 return (GNM_SOW_ADJUSTMENT (so
)->horizontal
);
1379 sheet_widget_adjustment_set_link (SheetObject
*so
, GnmExprTop
const *texpr
)
1381 SheetWidgetAdjustment
*swa
= GNM_SOW_ADJUSTMENT (so
);
1382 dependent_set_expr (&swa
->dep
, texpr
);
1383 if (texpr
&& swa
->dep
.sheet
)
1384 dependent_link (&swa
->dep
);
1388 sheet_widget_adjustment_get_link (SheetObject
*so
)
1390 SheetWidgetAdjustment
*swa
= GNM_SOW_ADJUSTMENT (so
);
1391 GnmExprTop
const *texpr
= swa
->dep
.texpr
;
1394 gnm_expr_top_ref (texpr
);
1401 adjustment_eval (GnmDependent
*dep
)
1406 v
= gnm_expr_top_eval (dep
->texpr
, eval_pos_init_dep (&pos
, dep
),
1407 GNM_EXPR_EVAL_SCALAR_NON_EMPTY
);
1408 sheet_widget_adjustment_set_value (DEP_TO_ADJUSTMENT(dep
),
1409 value_get_as_float (v
));
1414 adjustment_debug_name (GnmDependent
const *dep
, GString
*target
)
1416 g_string_append_printf (target
, "Adjustment%p", (void *)dep
);
1419 static DEPENDENT_MAKE_TYPE (adjustment
, NULL
)
1422 cb_adjustment_widget_value_changed (GtkWidget
*widget
,
1423 SheetWidgetAdjustment
*swa
)
1427 if (swa
->being_updated
)
1430 if (so_get_ref (GNM_SO (swa
), &ref
, TRUE
) != NULL
) {
1431 GnmCell
*cell
= sheet_cell_fetch (ref
.sheet
, ref
.col
, ref
.row
);
1432 /* TODO : add more control for precision, XL is stupid */
1433 int new_val
= gnm_fake_round (gtk_adjustment_get_value (swa
->adjustment
));
1434 if (cell
->value
!= NULL
&&
1435 VALUE_IS_FLOAT (cell
->value
) &&
1436 value_get_as_float (cell
->value
) == new_val
)
1439 swa
->being_updated
= TRUE
;
1440 cmd_so_set_value (widget_wbc (widget
),
1441 /* FIXME: This text sucks: */
1443 &ref
, value_new_int (new_val
),
1444 sheet_object_get_sheet (GNM_SO (swa
)));
1445 swa
->being_updated
= FALSE
;
1450 sheet_widget_adjustment_set_horizontal (SheetObject
*so
,
1451 gboolean horizontal
)
1453 SheetWidgetAdjustment
*swa
= (SheetWidgetAdjustment
*)so
;
1457 if (!SWA_CLASS (swa
)->has_orientation
)
1459 horizontal
= !!horizontal
;
1460 if (horizontal
== swa
->horizontal
)
1462 swa
->horizontal
= horizontal
;
1463 o
= horizontal
? GTK_ORIENTATION_HORIZONTAL
: GTK_ORIENTATION_VERTICAL
;
1465 /* Change direction for all realized widgets. */
1466 for (ptr
= swa
->sow
.so
.realized_list
; ptr
!= NULL
; ptr
= ptr
->next
) {
1467 SheetObjectView
*view
= ptr
->data
;
1468 GocWidget
*item
= get_goc_widget (view
);
1469 gtk_orientable_set_orientation (GTK_ORIENTABLE (item
->widget
), o
);
1475 sheet_widget_adjustment_get_property (GObject
*obj
, guint param_id
,
1476 GValue
*value
, GParamSpec
*pspec
)
1478 SheetWidgetAdjustment
*swa
= GNM_SOW_ADJUSTMENT (obj
);
1481 case SWA_PROP_HORIZONTAL
:
1482 g_value_set_boolean (value
, swa
->horizontal
);
1485 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj
, param_id
, pspec
);
1491 sheet_widget_adjustment_set_property (GObject
*obj
, guint param_id
,
1492 GValue
const *value
, GParamSpec
*pspec
)
1494 SheetWidgetAdjustment
*swa
= GNM_SOW_ADJUSTMENT (obj
);
1497 case SWA_PROP_HORIZONTAL
:
1498 sheet_widget_adjustment_set_horizontal (GNM_SO (swa
), g_value_get_boolean (value
));
1501 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj
, param_id
, pspec
);
1507 sheet_widget_adjustment_init_full (SheetWidgetAdjustment
*swa
,
1508 GnmCellRef
const *ref
,
1509 gboolean horizontal
)
1512 g_return_if_fail (swa
!= NULL
);
1515 so
->flags
&= ~SHEET_OBJECT_PRINT
;
1517 swa
->adjustment
= GTK_ADJUSTMENT (gtk_adjustment_new (0., 0., 100., 1., 10., 0.));
1518 g_object_ref_sink (swa
->adjustment
);
1520 swa
->horizontal
= horizontal
;
1521 swa
->being_updated
= FALSE
;
1522 swa
->dep
.sheet
= NULL
;
1523 swa
->dep
.flags
= adjustment_get_dep_type ();
1524 swa
->dep
.texpr
= (ref
!= NULL
)
1525 ? gnm_expr_top_new (gnm_expr_new_cellref (ref
))
1530 sheet_widget_adjustment_init (SheetWidgetAdjustment
*swa
)
1532 sheet_widget_adjustment_init_full (swa
, NULL
, FALSE
);
1536 sheet_widget_adjustment_finalize (GObject
*obj
)
1538 SheetWidgetAdjustment
*swa
= GNM_SOW_ADJUSTMENT (obj
);
1540 g_return_if_fail (swa
!= NULL
);
1542 dependent_set_expr (&swa
->dep
, NULL
);
1543 if (swa
->adjustment
!= NULL
) {
1544 g_object_unref (swa
->adjustment
);
1545 swa
->adjustment
= NULL
;
1548 sheet_object_widget_class
->finalize (obj
);
1552 sheet_widget_adjustment_copy (SheetObject
*dst
, SheetObject
const *src
)
1554 SheetWidgetAdjustment
const *src_swa
= GNM_SOW_ADJUSTMENT (src
);
1555 SheetWidgetAdjustment
*dst_swa
= GNM_SOW_ADJUSTMENT (dst
);
1556 GtkAdjustment
*dst_adjust
, *src_adjust
;
1559 sheet_widget_adjustment_init_full (dst_swa
,
1560 so_get_ref (src
, &ref
, FALSE
),
1561 src_swa
->horizontal
);
1562 dst_adjust
= dst_swa
->adjustment
;
1563 src_adjust
= src_swa
->adjustment
;
1565 gtk_adjustment_configure
1567 gtk_adjustment_get_value (src_adjust
),
1568 gtk_adjustment_get_lower (src_adjust
),
1569 gtk_adjustment_get_upper (src_adjust
),
1570 gtk_adjustment_get_step_increment (src_adjust
),
1571 gtk_adjustment_get_page_increment (src_adjust
),
1572 gtk_adjustment_get_page_size (src_adjust
));
1577 GnmExprEntry
*expression
;
1582 GtkWidget
*direction_h
;
1583 GtkWidget
*direction_v
;
1586 GtkWidget
*old_focus
;
1589 SheetWidgetAdjustment
*swa
;
1591 } AdjustmentConfigState
;
1594 cb_adjustment_set_focus (G_GNUC_UNUSED GtkWidget
*window
, GtkWidget
*focus_widget
,
1595 AdjustmentConfigState
*state
)
1599 /* Note: half of the set-focus action is handle by the default
1600 * callback installed by wbc_gtk_attach_guru. */
1602 ofp
= state
->old_focus
1603 ? gtk_widget_get_parent (state
->old_focus
)
1605 /* Force an update of the content in case it needs tweaking (eg make it
1607 if (ofp
&& GNM_EXPR_ENTRY_IS (ofp
)) {
1609 GnmExprTop
const *texpr
= gnm_expr_entry_parse (
1610 GNM_EXPR_ENTRY (ofp
),
1611 parse_pos_init_sheet (&pp
, state
->sheet
),
1612 NULL
, FALSE
, GNM_EXPR_PARSE_DEFAULT
);
1614 gnm_expr_top_unref (texpr
);
1616 state
->old_focus
= focus_widget
;
1620 cb_adjustment_config_destroy (AdjustmentConfigState
*state
)
1622 g_return_if_fail (state
!= NULL
);
1624 g_free (state
->undo_label
);
1626 state
->dialog
= NULL
;
1631 cb_adjustment_config_ok_clicked (G_GNUC_UNUSED GtkWidget
*button
, AdjustmentConfigState
*state
)
1633 SheetObject
*so
= GNM_SO (state
->swa
);
1635 GnmExprTop
const *texpr
= gnm_expr_entry_parse (state
->expression
,
1636 parse_pos_init_sheet (&pp
, so
->sheet
),
1637 NULL
, FALSE
, GNM_EXPR_PARSE_DEFAULT
);
1638 gboolean horizontal
;
1640 horizontal
= state
->direction_h
1641 ? gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (state
->direction_h
))
1642 : state
->swa
->horizontal
;
1644 cmd_so_set_adjustment (GNM_WBC (state
->wbcg
), so
,
1647 gtk_spin_button_get_value_as_int (
1648 GTK_SPIN_BUTTON (state
->min
)),
1649 gtk_spin_button_get_value_as_int (
1650 GTK_SPIN_BUTTON (state
->max
)),
1651 gtk_spin_button_get_value_as_int (
1652 GTK_SPIN_BUTTON (state
->inc
)),
1653 gtk_spin_button_get_value_as_int (
1654 GTK_SPIN_BUTTON (state
->page
)),
1657 gtk_widget_destroy (state
->dialog
);
1661 cb_adjustment_config_cancel_clicked (G_GNUC_UNUSED GtkWidget
*button
, AdjustmentConfigState
*state
)
1663 gtk_widget_destroy (state
->dialog
);
1667 sheet_widget_adjustment_user_config_impl (SheetObject
*so
, SheetControl
*sc
, char const *undo_label
, char const *dialog_label
)
1669 SheetWidgetAdjustment
*swa
= GNM_SOW_ADJUSTMENT (so
);
1670 SheetWidgetAdjustmentClass
*swa_class
= SWA_CLASS (swa
);
1671 WBCGtk
*wbcg
= scg_wbcg (GNM_SCG (sc
));
1672 AdjustmentConfigState
*state
;
1675 gboolean has_directions
= swa_class
->has_orientation
;
1677 /* Only pop up one copy per workbook */
1678 if (gnm_dialog_raise_if_exists (wbcg
, SHEET_OBJECT_CONFIG_KEY
))
1681 gui
= gnm_gtk_builder_load ("res:ui/so-scrollbar.ui", NULL
, GO_CMD_CONTEXT (wbcg
));
1684 state
= g_new (AdjustmentConfigState
, 1);
1687 state
->sheet
= sc_sheet (sc
);
1688 state
->old_focus
= NULL
;
1689 state
->undo_label
= (undo_label
== NULL
) ? NULL
: g_strdup (undo_label
);
1690 state
->dialog
= go_gtk_builder_get_widget (gui
, "SO-Scrollbar");
1692 if (dialog_label
!= NULL
)
1693 gtk_window_set_title (GTK_WINDOW (state
->dialog
), dialog_label
);
1695 grid
= go_gtk_builder_get_widget (gui
, "main-grid");
1697 state
->expression
= gnm_expr_entry_new (wbcg
, TRUE
);
1698 gnm_expr_entry_set_flags (state
->expression
,
1699 GNM_EE_FORCE_ABS_REF
| GNM_EE_SHEET_OPTIONAL
| GNM_EE_SINGLE_RANGE
,
1701 gnm_expr_entry_load_from_dep (state
->expression
, &swa
->dep
);
1702 go_atk_setup_label (go_gtk_builder_get_widget (gui
, "label_linkto"),
1703 GTK_WIDGET (state
->expression
));
1704 gtk_grid_attach (GTK_GRID (grid
),
1705 GTK_WIDGET (state
->expression
), 1, 0, 2, 1);
1706 gtk_widget_show (GTK_WIDGET (state
->expression
));
1708 if (has_directions
) {
1709 state
->direction_h
= go_gtk_builder_get_widget (gui
, "direction_h");
1710 state
->direction_v
= go_gtk_builder_get_widget (gui
, "direction_v");
1711 gtk_toggle_button_set_active
1712 (GTK_TOGGLE_BUTTON (swa
->horizontal
1713 ? state
->direction_h
1714 : state
->direction_v
),
1717 state
->direction_h
= NULL
;
1718 state
->direction_v
= NULL
;
1719 gtk_widget_destroy (go_gtk_builder_get_widget (gui
, "direction_label"));
1720 gtk_widget_destroy (go_gtk_builder_get_widget (gui
, "direction_h"));
1721 gtk_widget_destroy (go_gtk_builder_get_widget (gui
, "direction_v"));
1724 /* TODO : This is silly, no need to be similar to XL here. */
1725 state
->min
= go_gtk_builder_get_widget (gui
, "spin_min");
1726 gtk_spin_button_set_value (GTK_SPIN_BUTTON (state
->min
),
1727 gtk_adjustment_get_lower (swa
->adjustment
));
1728 state
->max
= go_gtk_builder_get_widget (gui
, "spin_max");
1729 gtk_spin_button_set_value (GTK_SPIN_BUTTON (state
->max
),
1730 gtk_adjustment_get_upper (swa
->adjustment
));
1731 state
->inc
= go_gtk_builder_get_widget (gui
, "spin_increment");
1732 gtk_spin_button_set_value (GTK_SPIN_BUTTON (state
->inc
),
1733 gtk_adjustment_get_step_increment (swa
->adjustment
));
1734 state
->page
= go_gtk_builder_get_widget (gui
, "spin_page");
1735 gtk_spin_button_set_value (GTK_SPIN_BUTTON (state
->page
),
1736 gtk_adjustment_get_page_increment (swa
->adjustment
));
1738 gnm_editable_enters (GTK_WINDOW (state
->dialog
),
1739 GTK_WIDGET (state
->expression
));
1740 gnm_editable_enters (GTK_WINDOW (state
->dialog
),
1741 GTK_WIDGET (state
->min
));
1742 gnm_editable_enters (GTK_WINDOW (state
->dialog
),
1743 GTK_WIDGET (state
->max
));
1744 gnm_editable_enters (GTK_WINDOW (state
->dialog
),
1745 GTK_WIDGET (state
->inc
));
1746 gnm_editable_enters (GTK_WINDOW (state
->dialog
),
1747 GTK_WIDGET (state
->page
));
1748 g_signal_connect (G_OBJECT (go_gtk_builder_get_widget (gui
, "ok_button")),
1750 G_CALLBACK (cb_adjustment_config_ok_clicked
), state
);
1751 g_signal_connect (G_OBJECT (go_gtk_builder_get_widget (gui
, "cancel_button")),
1753 G_CALLBACK (cb_adjustment_config_cancel_clicked
), state
);
1755 gnm_init_help_button (
1756 go_gtk_builder_get_widget (gui
, "help_button"),
1757 GNUMERIC_HELP_LINK_SO_ADJUSTMENT
);
1759 gnm_keyed_dialog (state
->wbcg
, GTK_WINDOW (state
->dialog
),
1760 SHEET_OBJECT_CONFIG_KEY
);
1762 wbc_gtk_attach_guru (state
->wbcg
, state
->dialog
);
1763 g_object_set_data_full (G_OBJECT (state
->dialog
),
1764 "state", state
, (GDestroyNotify
) cb_adjustment_config_destroy
);
1766 /* Note: half of the set-focus action is handle by the default */
1767 /* callback installed by wbc_gtk_attach_guru */
1768 g_signal_connect (G_OBJECT (state
->dialog
), "set-focus",
1769 G_CALLBACK (cb_adjustment_set_focus
), state
);
1770 g_object_unref (gui
);
1772 gtk_widget_show (state
->dialog
);
1776 sheet_widget_adjustment_user_config (SheetObject
*so
, SheetControl
*sc
)
1778 sheet_widget_adjustment_user_config_impl (so
, sc
, N_("Configure Adjustment"),
1779 N_("Adjustment Properties"));
1783 sheet_widget_adjustment_set_sheet (SheetObject
*so
, Sheet
*sheet
)
1785 SheetWidgetAdjustment
*swa
= GNM_SOW_ADJUSTMENT (so
);
1787 dependent_set_sheet (&swa
->dep
, sheet
);
1793 sheet_widget_adjustment_foreach_dep (SheetObject
*so
,
1794 SheetObjectForeachDepFunc func
,
1797 SheetWidgetAdjustment
*swa
= GNM_SOW_ADJUSTMENT (so
);
1798 func (&swa
->dep
, so
, user
);
1802 sheet_widget_adjustment_write_xml_sax (SheetObject
const *so
, GsfXMLOut
*output
,
1803 GnmConventions
const *convs
)
1805 SheetWidgetAdjustment
const *swa
= GNM_SOW_ADJUSTMENT (so
);
1806 SheetWidgetAdjustmentClass
*swa_class
= SWA_CLASS (so
);
1808 go_xml_out_add_double (output
, "Min", gtk_adjustment_get_lower (swa
->adjustment
));
1809 go_xml_out_add_double (output
, "Max", gtk_adjustment_get_upper (swa
->adjustment
));
1810 go_xml_out_add_double (output
, "Inc", gtk_adjustment_get_step_increment (swa
->adjustment
));
1811 go_xml_out_add_double (output
, "Page", gtk_adjustment_get_page_increment (swa
->adjustment
));
1812 go_xml_out_add_double (output
, "Value", gtk_adjustment_get_value (swa
->adjustment
));
1814 if (swa_class
->has_orientation
)
1815 gsf_xml_out_add_bool (output
, "Horizontal", swa
->horizontal
);
1817 sax_write_dep (output
, &swa
->dep
, "Input", convs
);
1821 sheet_widget_adjustment_prep_sax_parser (SheetObject
*so
, GsfXMLIn
*xin
,
1822 xmlChar
const **attrs
,
1823 GnmConventions
const *convs
)
1825 SheetWidgetAdjustment
*swa
= GNM_SOW_ADJUSTMENT (so
);
1826 SheetWidgetAdjustmentClass
*swa_class
= SWA_CLASS (so
);
1827 swa
->horizontal
= FALSE
;
1829 for (; attrs
!= NULL
&& attrs
[0] && attrs
[1] ; attrs
+= 2) {
1833 if (gnm_xml_attr_double (attrs
, "Min", &tmp
))
1834 gtk_adjustment_set_lower (swa
->adjustment
, tmp
);
1835 else if (gnm_xml_attr_double (attrs
, "Max", &tmp
))
1836 gtk_adjustment_set_upper (swa
->adjustment
, tmp
); /* allow scrolling to max */
1837 else if (gnm_xml_attr_double (attrs
, "Inc", &tmp
))
1838 gtk_adjustment_set_step_increment (swa
->adjustment
, tmp
);
1839 else if (gnm_xml_attr_double (attrs
, "Page", &tmp
))
1840 gtk_adjustment_set_page_increment (swa
->adjustment
, tmp
);
1841 else if (gnm_xml_attr_double (attrs
, "Value", &tmp
))
1842 gtk_adjustment_set_value (swa
->adjustment
, tmp
);
1843 else if (sax_read_dep (attrs
, "Input", &swa
->dep
, xin
, convs
))
1845 else if (swa_class
->has_orientation
&&
1846 gnm_xml_attr_bool (attrs
, "Horizontal", &b
))
1847 swa
->horizontal
= b
;
1850 swa
->dep
.flags
= adjustment_get_dep_type ();
1854 sheet_widget_adjustment_set_details (SheetObject
*so
, GnmExprTop
const *tlink
,
1855 int value
, int min
, int max
,
1858 SheetWidgetAdjustment
*swa
= GNM_SOW_ADJUSTMENT (so
);
1861 g_return_if_fail (swa
!= NULL
);
1863 dependent_set_expr (&swa
->dep
, tlink
);
1864 if (tlink
&& swa
->dep
.sheet
)
1865 dependent_link (&swa
->dep
);
1867 page_size
= gtk_adjustment_get_page_size (swa
->adjustment
); /* ??? */
1868 gtk_adjustment_configure (swa
->adjustment
,
1869 value
, min
, max
, inc
, page
, page_size
);
1873 sheet_widget_adjustment_create_widget (G_GNUC_UNUSED SheetObjectWidget
*sow
)
1875 g_assert_not_reached ();
1879 SOW_MAKE_TYPE (adjustment
, Adjustment
,
1880 sheet_widget_adjustment_user_config
,
1881 sheet_widget_adjustment_set_sheet
,
1883 sheet_widget_adjustment_foreach_dep
,
1884 sheet_widget_adjustment_copy
,
1885 sheet_widget_adjustment_write_xml_sax
,
1886 sheet_widget_adjustment_prep_sax_parser
,
1887 sheet_widget_adjustment_get_property
,
1888 sheet_widget_adjustment_set_property
,
1889 sheet_widget_draw_cairo
,
1891 ((SheetWidgetAdjustmentClass
*) object_class
)->has_orientation
= TRUE
;
1892 g_object_class_install_property
1893 (object_class
, SWA_PROP_HORIZONTAL
,
1894 g_param_spec_boolean ("horizontal", NULL
, NULL
,
1896 GSF_PARAM_STATIC
| G_PARAM_READWRITE
));
1899 /****************************************************************************/
1901 #define GNM_SOW_SCROLLBAR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNM_SOW_SCROLLBAR_TYPE, SheetWidgetScrollbar))
1902 #define DEP_TO_SCROLLBAR(d_ptr) (SheetWidgetScrollbar *)(((char *)d_ptr) - G_STRUCT_OFFSET(SheetWidgetScrollbar, dep))
1904 typedef SheetWidgetAdjustment SheetWidgetScrollbar
;
1905 typedef SheetWidgetAdjustmentClass SheetWidgetScrollbarClass
;
1908 sheet_widget_scrollbar_create_widget (SheetObjectWidget
*sow
)
1910 SheetWidgetAdjustment
*swa
= GNM_SOW_ADJUSTMENT (sow
);
1913 swa
->being_updated
= TRUE
;
1914 bar
= gtk_scrollbar_new (swa
->horizontal
? GTK_ORIENTATION_HORIZONTAL
: GTK_ORIENTATION_VERTICAL
, swa
->adjustment
);
1915 gtk_widget_set_can_focus (bar
, FALSE
);
1916 g_signal_connect (G_OBJECT (bar
),
1918 G_CALLBACK (cb_adjustment_widget_value_changed
), swa
);
1919 g_signal_connect (G_OBJECT (bar
), "destroy",
1920 G_CALLBACK (cb_range_destroyed
), swa
);
1921 swa
->being_updated
= FALSE
;
1927 sheet_widget_scrollbar_user_config (SheetObject
*so
, SheetControl
*sc
)
1929 sheet_widget_adjustment_user_config_impl (so
, sc
, N_("Configure Scrollbar"),
1930 N_("Scrollbar Properties"));
1933 static void sheet_widget_slider_horizontal_draw_cairo
1934 (SheetObject
const *so
, cairo_t
*cr
, double width
, double height
);
1937 sheet_widget_scrollbar_horizontal_draw_cairo (SheetObject
const *so
, cairo_t
*cr
,
1938 double width
, double height
)
1941 cairo_set_source_rgb(cr
, 0.5, 0.5, 0.5);
1943 cairo_new_path (cr
);
1944 cairo_move_to (cr
, 0., height
/2);
1945 cairo_rel_line_to (cr
, 15., 7.5);
1946 cairo_rel_line_to (cr
, 0, -15);
1947 cairo_close_path (cr
);
1950 cairo_new_path (cr
);
1951 cairo_move_to (cr
, width
, height
/2);
1952 cairo_rel_line_to (cr
, -15., 7.5);
1953 cairo_rel_line_to (cr
, 0, -15);
1954 cairo_close_path (cr
);
1957 cairo_new_path (cr
);
1958 cairo_translate (cr
, 15., 0.);
1959 sheet_widget_slider_horizontal_draw_cairo (so
, cr
, width
- 30, height
);
1964 sheet_widget_scrollbar_vertical_draw_cairo (SheetObject
const *so
, cairo_t
*cr
,
1965 double width
, double height
)
1968 cairo_rotate (cr
, M_PI
/2);
1969 cairo_translate (cr
, 0., -width
);
1970 sheet_widget_scrollbar_horizontal_draw_cairo (so
, cr
, height
, width
);
1975 sheet_widget_scrollbar_draw_cairo (SheetObject
const *so
, cairo_t
*cr
,
1976 double width
, double height
)
1978 SheetWidgetAdjustment
*swa
= GNM_SOW_ADJUSTMENT (so
);
1979 if (swa
->horizontal
)
1980 sheet_widget_scrollbar_horizontal_draw_cairo
1981 (so
, cr
, width
, height
);
1983 sheet_widget_scrollbar_vertical_draw_cairo
1984 (so
, cr
, width
, height
);
1988 sheet_widget_scrollbar_class_init (SheetObjectWidgetClass
*sow_class
)
1990 SheetWidgetAdjustmentClass
*swa_class
= (SheetWidgetAdjustmentClass
*)sow_class
;
1991 SheetObjectClass
*so_class
= GNM_SO_CLASS (sow_class
);
1993 sow_class
->create_widget
= &sheet_widget_scrollbar_create_widget
;
1994 so_class
->user_config
= &sheet_widget_scrollbar_user_config
;
1995 so_class
->draw_cairo
= &sheet_widget_scrollbar_draw_cairo
;
1996 swa_class
->type
= GTK_TYPE_SCROLLBAR
;
1999 GSF_CLASS (SheetWidgetScrollbar
, sheet_widget_scrollbar
,
2000 &sheet_widget_scrollbar_class_init
, NULL
,
2001 GNM_SOW_ADJUSTMENT_TYPE
)
2003 /****************************************************************************/
2005 #define GNM_SOW_SPIN_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNM_SOW_SPIN_BUTTON_TYPE, SheetWidgetSpinbutton))
2006 #define DEP_TO_SPINBUTTON(d_ptr) (SheetWidgetSpinbutton *)(((char *)d_ptr) - G_STRUCT_OFFSET(SheetWidgetSpinbutton, dep))
2008 typedef SheetWidgetAdjustment SheetWidgetSpinbutton
;
2009 typedef SheetWidgetAdjustmentClass SheetWidgetSpinbuttonClass
;
2012 sheet_widget_spinbutton_create_widget (SheetObjectWidget
*sow
)
2014 SheetWidgetAdjustment
*swa
= GNM_SOW_ADJUSTMENT (sow
);
2015 GtkWidget
*spinbutton
;
2017 swa
->being_updated
= TRUE
;
2018 spinbutton
= gtk_spin_button_new
2020 gtk_adjustment_get_step_increment (swa
->adjustment
),
2022 gtk_widget_set_can_focus (spinbutton
, FALSE
);
2023 g_signal_connect (G_OBJECT (spinbutton
),
2025 G_CALLBACK (cb_adjustment_widget_value_changed
), swa
);
2026 g_signal_connect (G_OBJECT (spinbutton
), "destroy",
2027 G_CALLBACK (cb_range_destroyed
), swa
);
2028 swa
->being_updated
= FALSE
;
2033 sheet_widget_spinbutton_user_config (SheetObject
*so
, SheetControl
*sc
)
2035 sheet_widget_adjustment_user_config_impl (so
, sc
, N_("Configure Spinbutton"),
2036 N_("Spinbutton Properties"));
2040 sheet_widget_spinbutton_draw_cairo (SheetObject
const *so
, cairo_t
*cr
,
2041 double width
, double height
)
2043 SheetWidgetAdjustment
*swa
= GNM_SOW_ADJUSTMENT (so
);
2044 GtkAdjustment
*adjustment
= swa
->adjustment
;
2045 double value
= gtk_adjustment_get_value (adjustment
);
2046 int ivalue
= (int) value
;
2047 double halfheight
= height
/2;
2051 cairo_set_line_width (cr
, 0.5);
2052 cairo_set_source_rgb(cr
, 0, 0, 0);
2054 cairo_new_path (cr
);
2055 cairo_move_to (cr
, 0, 0);
2056 cairo_line_to (cr
, width
, 0);
2057 cairo_line_to (cr
, width
, height
);
2058 cairo_line_to (cr
, 0, height
);
2059 cairo_close_path (cr
);
2062 cairo_new_path (cr
);
2063 cairo_move_to (cr
, width
- 10, 0);
2064 cairo_rel_line_to (cr
, 0, height
);
2067 cairo_set_source_rgb(cr
, 0.5, 0.5, 0.5);
2069 cairo_new_path (cr
);
2070 cairo_move_to (cr
, width
- 5, 3);
2071 cairo_rel_line_to (cr
, 3, 3);
2072 cairo_rel_line_to (cr
, -6, 0);
2073 cairo_close_path (cr
);
2076 cairo_new_path (cr
);
2077 cairo_move_to (cr
, width
- 5, height
- 3);
2078 cairo_rel_line_to (cr
, 3, -3);
2079 cairo_rel_line_to (cr
, -6, 0);
2080 cairo_close_path (cr
);
2083 str
= g_strdup_printf ("%i", ivalue
);
2084 cairo_set_source_rgb(cr
, 0, 0, 0);
2085 cairo_move_to (cr
, 4., halfheight
);
2086 draw_cairo_text (cr
, str
, NULL
, NULL
, TRUE
, FALSE
, TRUE
, 0, FALSE
);
2089 cairo_new_path (cr
);
2094 sheet_widget_spinbutton_class_init (SheetObjectWidgetClass
*sow_class
)
2096 SheetWidgetAdjustmentClass
*swa_class
= (SheetWidgetAdjustmentClass
*)sow_class
;
2097 SheetObjectClass
*so_class
= GNM_SO_CLASS (sow_class
);
2099 sow_class
->create_widget
= &sheet_widget_spinbutton_create_widget
;
2100 so_class
->user_config
= &sheet_widget_spinbutton_user_config
;
2101 so_class
->draw_cairo
= &sheet_widget_spinbutton_draw_cairo
;
2103 swa_class
->type
= GTK_TYPE_SPIN_BUTTON
;
2104 swa_class
->has_orientation
= FALSE
;
2107 GSF_CLASS (SheetWidgetSpinbutton
, sheet_widget_spinbutton
,
2108 &sheet_widget_spinbutton_class_init
, NULL
,
2109 GNM_SOW_ADJUSTMENT_TYPE
)
2111 /****************************************************************************/
2113 #define GNM_SOW_SLIDER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNM_SOW_SLIDER_TYPE, SheetWidgetSlider))
2114 #define DEP_TO_SLIDER(d_ptr) (SheetWidgetSlider *)(((char *)d_ptr) - G_STRUCT_OFFSET(SheetWidgetSlider, dep))
2116 typedef SheetWidgetAdjustment SheetWidgetSlider
;
2117 typedef SheetWidgetAdjustmentClass SheetWidgetSliderClass
;
2120 sheet_widget_slider_create_widget (SheetObjectWidget
*sow
)
2122 SheetWidgetAdjustment
*swa
= GNM_SOW_ADJUSTMENT (sow
);
2125 swa
->being_updated
= TRUE
;
2126 slider
= gtk_scale_new (swa
->horizontal
? GTK_ORIENTATION_HORIZONTAL
: GTK_ORIENTATION_VERTICAL
, swa
->adjustment
);
2127 gtk_scale_set_draw_value (GTK_SCALE (slider
), FALSE
);
2128 gtk_widget_set_can_focus (slider
, FALSE
);
2129 g_signal_connect (G_OBJECT (slider
),
2131 G_CALLBACK (cb_adjustment_widget_value_changed
), swa
);
2132 g_signal_connect (G_OBJECT (slider
), "destroy",
2133 G_CALLBACK (cb_range_destroyed
), swa
);
2134 swa
->being_updated
= FALSE
;
2140 sheet_widget_slider_user_config (SheetObject
*so
, SheetControl
*sc
)
2142 sheet_widget_adjustment_user_config_impl (so
, sc
, N_("Configure Slider"),
2143 N_("Slider Properties"));
2147 sheet_widget_slider_horizontal_draw_cairo (SheetObject
const *so
, cairo_t
*cr
,
2148 double width
, double height
)
2150 SheetWidgetAdjustment
*swa
= GNM_SOW_ADJUSTMENT (so
);
2151 GtkAdjustment
*adjustment
= swa
->adjustment
;
2152 double value
= gtk_adjustment_get_value (adjustment
);
2153 double upper
= gtk_adjustment_get_upper (adjustment
);
2154 double lower
= gtk_adjustment_get_lower (adjustment
);
2155 double fraction
= (upper
== lower
) ? 0.0 : (value
- lower
)/(upper
- lower
);
2158 cairo_set_line_width (cr
, 5);
2159 cairo_set_source_rgb(cr
, 0.8, 0.8, 0.8);
2160 cairo_set_line_cap (cr
, CAIRO_LINE_CAP_ROUND
);
2162 cairo_new_path (cr
);
2163 cairo_move_to (cr
, 4, height
/2);
2164 cairo_rel_line_to (cr
, width
- 8., 0);
2167 cairo_set_line_width (cr
, 15);
2168 cairo_set_source_rgb(cr
, 0.5, 0.5, 0.5);
2169 cairo_set_line_cap (cr
, CAIRO_LINE_CAP_ROUND
);
2171 cairo_new_path (cr
);
2172 cairo_move_to (cr
, fraction
* (width
- 8. - 1. - 5. - 5. + 2.5 + 2.5)
2173 - 10. + 10. + 4. + 5. - 2.5, height
/2);
2174 cairo_rel_line_to (cr
, 1, 0);
2177 cairo_new_path (cr
);
2182 sheet_widget_slider_vertical_draw_cairo (SheetObject
const *so
, cairo_t
*cr
,
2183 double width
, double height
)
2186 cairo_rotate (cr
, M_PI
/2);
2187 cairo_translate (cr
, 0., -width
);
2188 sheet_widget_slider_horizontal_draw_cairo (so
, cr
, height
, width
);
2193 sheet_widget_slider_draw_cairo (SheetObject
const *so
, cairo_t
*cr
,
2194 double width
, double height
)
2196 SheetWidgetAdjustment
*swa
= GNM_SOW_ADJUSTMENT (so
);
2197 if (swa
->horizontal
)
2198 sheet_widget_slider_horizontal_draw_cairo (so
, cr
, width
, height
);
2200 sheet_widget_slider_vertical_draw_cairo (so
, cr
, width
, height
);
2204 sheet_widget_slider_class_init (SheetObjectWidgetClass
*sow_class
)
2206 SheetWidgetAdjustmentClass
*swa_class
= (SheetWidgetAdjustmentClass
*)sow_class
;
2207 SheetObjectClass
*so_class
= GNM_SO_CLASS (sow_class
);
2209 sow_class
->create_widget
= &sheet_widget_slider_create_widget
;
2210 so_class
->user_config
= &sheet_widget_slider_user_config
;
2211 so_class
->draw_cairo
= &sheet_widget_slider_draw_cairo
;
2213 swa_class
->type
= GTK_TYPE_SCALE
;
2216 GSF_CLASS (SheetWidgetSlider
, sheet_widget_slider
,
2217 &sheet_widget_slider_class_init
, NULL
,
2218 GNM_SOW_ADJUSTMENT_TYPE
)
2220 /****************************************************************************/
2222 #define GNM_SOW_CHECKBOX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNM_SOW_CHECKBOX_TYPE, SheetWidgetCheckbox))
2223 #define DEP_TO_CHECKBOX(d_ptr) (SheetWidgetCheckbox *)(((char *)d_ptr) - G_STRUCT_OFFSET(SheetWidgetCheckbox, dep))
2226 SheetObjectWidget sow
;
2231 gboolean being_updated
;
2232 } SheetWidgetCheckbox
;
2233 typedef SheetObjectWidgetClass SheetWidgetCheckboxClass
;
2243 sheet_widget_checkbox_set_active (SheetWidgetCheckbox
*swc
)
2247 swc
->being_updated
= TRUE
;
2249 for (ptr
= swc
->sow
.so
.realized_list
; ptr
!= NULL
; ptr
= ptr
->next
) {
2250 SheetObjectView
*view
= ptr
->data
;
2251 GocWidget
*item
= get_goc_widget (view
);
2252 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item
->widget
),
2256 g_object_notify (G_OBJECT (swc
), "active");
2258 swc
->being_updated
= FALSE
;
2262 sheet_widget_checkbox_get_property (GObject
*obj
, guint param_id
,
2263 GValue
*value
, GParamSpec
*pspec
)
2265 SheetWidgetCheckbox
*swc
= GNM_SOW_CHECKBOX (obj
);
2268 case SOC_PROP_ACTIVE
:
2269 g_value_set_boolean (value
, swc
->value
);
2272 g_value_set_string (value
, swc
->label
);
2274 case SOC_PROP_MARKUP
:
2275 g_value_set_boxed (value
, NULL
); /* swc->markup */
2278 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj
, param_id
, pspec
);
2284 sheet_widget_checkbox_set_property (GObject
*obj
, guint param_id
,
2285 GValue
const *value
, GParamSpec
*pspec
)
2287 SheetWidgetCheckbox
*swc
= GNM_SOW_CHECKBOX (obj
);
2290 case SOC_PROP_ACTIVE
:
2291 swc
->value
= g_value_get_boolean (value
);
2292 sheet_widget_checkbox_set_active (swc
);
2295 sheet_widget_checkbox_set_label (GNM_SO (swc
),
2296 g_value_get_string (value
));
2298 case SOC_PROP_MARKUP
:
2300 sheet_widget_checkbox_set_markup (GNM_SO (swc
),
2301 g_value_peek_pointer (value
));
2305 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj
, param_id
, pspec
);
2311 checkbox_eval (GnmDependent
*dep
)
2315 gboolean err
, result
;
2317 v
= gnm_expr_top_eval (dep
->texpr
, eval_pos_init_dep (&pos
, dep
),
2318 GNM_EXPR_EVAL_SCALAR_NON_EMPTY
);
2319 result
= value_get_as_bool (v
, &err
);
2322 SheetWidgetCheckbox
*swc
= DEP_TO_CHECKBOX(dep
);
2324 swc
->value
= result
;
2325 sheet_widget_checkbox_set_active (swc
);
2330 checkbox_debug_name (GnmDependent
const *dep
, GString
*target
)
2332 g_string_append_printf (target
, "Checkbox%p", (void *)dep
);
2335 static DEPENDENT_MAKE_TYPE (checkbox
, NULL
)
2338 sheet_widget_checkbox_init_full (SheetWidgetCheckbox
*swc
,
2339 GnmCellRef
const *ref
, char const *label
)
2341 static int counter
= 0;
2343 g_return_if_fail (swc
!= NULL
);
2345 swc
->label
= label
? g_strdup (label
) : g_strdup_printf (_("CheckBox %d"), ++counter
);
2346 swc
->being_updated
= FALSE
;
2348 swc
->dep
.sheet
= NULL
;
2349 swc
->dep
.flags
= checkbox_get_dep_type ();
2350 swc
->dep
.texpr
= (ref
!= NULL
)
2351 ? gnm_expr_top_new (gnm_expr_new_cellref (ref
))
2356 sheet_widget_checkbox_init (SheetWidgetCheckbox
*swc
)
2358 sheet_widget_checkbox_init_full (swc
, NULL
, NULL
);
2362 sheet_widget_checkbox_finalize (GObject
*obj
)
2364 SheetWidgetCheckbox
*swc
= GNM_SOW_CHECKBOX (obj
);
2366 g_return_if_fail (swc
!= NULL
);
2368 g_free (swc
->label
);
2371 dependent_set_expr (&swc
->dep
, NULL
);
2373 sheet_object_widget_class
->finalize (obj
);
2377 cb_checkbox_toggled (GtkToggleButton
*button
, SheetWidgetCheckbox
*swc
)
2381 if (swc
->being_updated
)
2383 swc
->value
= gtk_toggle_button_get_active (button
);
2384 sheet_widget_checkbox_set_active (swc
);
2386 if (so_get_ref (GNM_SO (swc
), &ref
, TRUE
) != NULL
) {
2387 gboolean new_val
= gtk_toggle_button_get_active (button
);
2388 cmd_so_set_value (widget_wbc (GTK_WIDGET (button
)),
2389 /* FIXME: This text sucks: */
2390 _("Clicking checkbox"),
2391 &ref
, value_new_bool (new_val
),
2392 sheet_object_get_sheet (GNM_SO (swc
)));
2397 sheet_widget_checkbox_create_widget (SheetObjectWidget
*sow
)
2399 SheetWidgetCheckbox
*swc
= GNM_SOW_CHECKBOX (sow
);
2402 g_return_val_if_fail (swc
!= NULL
, NULL
);
2404 button
= gtk_check_button_new_with_label (swc
->label
);
2405 gtk_widget_set_can_focus (button
, FALSE
);
2406 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button
), swc
->value
);
2407 g_signal_connect (G_OBJECT (button
),
2409 G_CALLBACK (cb_checkbox_toggled
), swc
);
2415 sheet_widget_checkbox_copy (SheetObject
*dst
, SheetObject
const *src
)
2417 SheetWidgetCheckbox
const *src_swc
= GNM_SOW_CHECKBOX (src
);
2418 SheetWidgetCheckbox
*dst_swc
= GNM_SOW_CHECKBOX (dst
);
2420 sheet_widget_checkbox_init_full (dst_swc
,
2421 so_get_ref (src
, &ref
, FALSE
),
2423 dst_swc
->value
= src_swc
->value
;
2428 GnmExprEntry
*expression
;
2432 GtkWidget
*old_focus
;
2435 SheetWidgetCheckbox
*swc
;
2437 } CheckboxConfigState
;
2440 cb_checkbox_set_focus (G_GNUC_UNUSED GtkWidget
*window
, GtkWidget
*focus_widget
,
2441 CheckboxConfigState
*state
)
2445 /* Note: half of the set-focus action is handle by the default
2446 * callback installed by wbc_gtk_attach_guru. */
2448 ofp
= state
->old_focus
2449 ? gtk_widget_get_parent (state
->old_focus
)
2452 /* Force an update of the content in case it needs tweaking (eg make it
2454 if (ofp
&& GNM_EXPR_ENTRY_IS (ofp
)) {
2456 GnmExprTop
const *texpr
= gnm_expr_entry_parse (
2457 GNM_EXPR_ENTRY (ofp
),
2458 parse_pos_init_sheet (&pp
, state
->sheet
),
2459 NULL
, FALSE
, GNM_EXPR_PARSE_DEFAULT
);
2461 gnm_expr_top_unref (texpr
);
2463 state
->old_focus
= focus_widget
;
2467 cb_checkbox_config_destroy (CheckboxConfigState
*state
)
2469 g_return_if_fail (state
!= NULL
);
2471 g_free (state
->old_label
);
2472 state
->old_label
= NULL
;
2473 state
->dialog
= NULL
;
2478 cb_checkbox_config_ok_clicked (G_GNUC_UNUSED GtkWidget
*button
, CheckboxConfigState
*state
)
2480 SheetObject
*so
= GNM_SO (state
->swc
);
2482 GnmExprTop
const *texpr
= gnm_expr_entry_parse (state
->expression
,
2483 parse_pos_init_sheet (&pp
, so
->sheet
),
2484 NULL
, FALSE
, GNM_EXPR_PARSE_DEFAULT
);
2485 gchar
const *text
= gtk_entry_get_text(GTK_ENTRY(state
->label
));
2487 cmd_so_set_checkbox (GNM_WBC (state
->wbcg
), so
,
2488 texpr
, g_strdup (state
->old_label
), g_strdup (text
));
2490 gtk_widget_destroy (state
->dialog
);
2494 cb_checkbox_config_cancel_clicked (G_GNUC_UNUSED GtkWidget
*button
, CheckboxConfigState
*state
)
2496 sheet_widget_checkbox_set_label (GNM_SO (state
->swc
),
2498 gtk_widget_destroy (state
->dialog
);
2502 cb_checkbox_label_changed (GtkEntry
*entry
, CheckboxConfigState
*state
)
2504 sheet_widget_checkbox_set_label (GNM_SO (state
->swc
),
2505 gtk_entry_get_text (entry
));
2509 sheet_widget_checkbox_user_config (SheetObject
*so
, SheetControl
*sc
)
2511 SheetWidgetCheckbox
*swc
= GNM_SOW_CHECKBOX (so
);
2512 WBCGtk
*wbcg
= scg_wbcg (GNM_SCG (sc
));
2513 CheckboxConfigState
*state
;
2517 g_return_if_fail (swc
!= NULL
);
2519 /* Only pop up one copy per workbook */
2520 if (gnm_dialog_raise_if_exists (wbcg
, SHEET_OBJECT_CONFIG_KEY
))
2523 gui
= gnm_gtk_builder_load ("res:ui/so-checkbox.ui", NULL
, GO_CMD_CONTEXT (wbcg
));
2526 state
= g_new (CheckboxConfigState
, 1);
2529 state
->sheet
= sc_sheet (sc
);
2530 state
->old_focus
= NULL
;
2531 state
->old_label
= g_strdup (swc
->label
);
2532 state
->dialog
= go_gtk_builder_get_widget (gui
, "SO-Checkbox");
2534 grid
= go_gtk_builder_get_widget (gui
, "main-grid");
2536 state
->expression
= gnm_expr_entry_new (wbcg
, TRUE
);
2537 gnm_expr_entry_set_flags (state
->expression
,
2538 GNM_EE_FORCE_ABS_REF
| GNM_EE_SHEET_OPTIONAL
| GNM_EE_SINGLE_RANGE
,
2540 gnm_expr_entry_load_from_dep (state
->expression
, &swc
->dep
);
2541 go_atk_setup_label (go_gtk_builder_get_widget (gui
, "label_linkto"),
2542 GTK_WIDGET (state
->expression
));
2543 gtk_grid_attach (GTK_GRID (grid
),
2544 GTK_WIDGET (state
->expression
), 1, 0, 1, 1);
2545 gtk_widget_show (GTK_WIDGET (state
->expression
));
2547 state
->label
= go_gtk_builder_get_widget (gui
, "label_entry");
2548 gtk_entry_set_text (GTK_ENTRY (state
->label
), swc
->label
);
2549 gtk_editable_select_region (GTK_EDITABLE(state
->label
), 0, -1);
2550 gnm_editable_enters (GTK_WINDOW (state
->dialog
),
2551 GTK_WIDGET (state
->expression
));
2552 gnm_editable_enters (GTK_WINDOW (state
->dialog
),
2553 GTK_WIDGET (state
->label
));
2555 g_signal_connect (G_OBJECT (state
->label
),
2557 G_CALLBACK (cb_checkbox_label_changed
), state
);
2558 g_signal_connect (G_OBJECT (go_gtk_builder_get_widget (gui
, "ok_button")),
2560 G_CALLBACK (cb_checkbox_config_ok_clicked
), state
);
2561 g_signal_connect (G_OBJECT (go_gtk_builder_get_widget (gui
, "cancel_button")),
2563 G_CALLBACK (cb_checkbox_config_cancel_clicked
), state
);
2565 gnm_init_help_button (
2566 go_gtk_builder_get_widget (gui
, "help_button"),
2567 GNUMERIC_HELP_LINK_SO_CHECKBOX
);
2569 gnm_keyed_dialog (state
->wbcg
, GTK_WINDOW (state
->dialog
),
2570 SHEET_OBJECT_CONFIG_KEY
);
2572 wbc_gtk_attach_guru (state
->wbcg
, state
->dialog
);
2573 g_object_set_data_full (G_OBJECT (state
->dialog
),
2574 "state", state
, (GDestroyNotify
) cb_checkbox_config_destroy
);
2576 /* Note: half of the set-focus action is handle by the default */
2577 /* callback installed by wbc_gtk_attach_guru */
2578 g_signal_connect (G_OBJECT (state
->dialog
), "set-focus",
2579 G_CALLBACK (cb_checkbox_set_focus
), state
);
2580 g_object_unref (gui
);
2582 gtk_widget_show (state
->dialog
);
2586 sheet_widget_checkbox_set_sheet (SheetObject
*so
, Sheet
*sheet
)
2588 SheetWidgetCheckbox
*swc
= GNM_SOW_CHECKBOX (so
);
2590 dependent_set_sheet (&swc
->dep
, sheet
);
2591 sheet_widget_checkbox_set_active (swc
);
2597 sheet_widget_checkbox_foreach_dep (SheetObject
*so
,
2598 SheetObjectForeachDepFunc func
,
2601 SheetWidgetCheckbox
*swc
= GNM_SOW_CHECKBOX (so
);
2602 func (&swc
->dep
, so
, user
);
2606 sheet_widget_checkbox_write_xml_sax (SheetObject
const *so
, GsfXMLOut
*output
,
2607 GnmConventions
const *convs
)
2609 SheetWidgetCheckbox
const *swc
= GNM_SOW_CHECKBOX (so
);
2610 gsf_xml_out_add_cstr (output
, "Label", swc
->label
);
2611 gsf_xml_out_add_int (output
, "Value", swc
->value
);
2612 sax_write_dep (output
, &swc
->dep
, "Input", convs
);
2616 sheet_widget_checkbox_prep_sax_parser (SheetObject
*so
, GsfXMLIn
*xin
,
2617 xmlChar
const **attrs
,
2618 GnmConventions
const *convs
)
2620 SheetWidgetCheckbox
*swc
= GNM_SOW_CHECKBOX (so
);
2622 for (; attrs
!= NULL
&& attrs
[0] && attrs
[1] ; attrs
+= 2)
2623 if (attr_eq (attrs
[0], "Label")) {
2624 g_free (swc
->label
);
2625 swc
->label
= g_strdup (CXML2C (attrs
[1]));
2626 } else if (gnm_xml_attr_int (attrs
, "Value", &swc
->value
))
2628 else if (sax_read_dep (attrs
, "Input", &swc
->dep
, xin
, convs
))
2633 sheet_widget_checkbox_set_link (SheetObject
*so
, GnmExprTop
const *texpr
)
2635 SheetWidgetCheckbox
*swc
= GNM_SOW_CHECKBOX (so
);
2636 dependent_set_expr (&swc
->dep
, texpr
);
2637 if (texpr
&& swc
->dep
.sheet
)
2638 dependent_link (&swc
->dep
);
2642 sheet_widget_checkbox_get_link (SheetObject
*so
)
2644 SheetWidgetCheckbox
*swc
= GNM_SOW_CHECKBOX (so
);
2645 GnmExprTop
const *texpr
= swc
->dep
.texpr
;
2648 gnm_expr_top_ref (texpr
);
2655 sheet_widget_checkbox_set_label (SheetObject
*so
, char const *str
)
2658 SheetWidgetCheckbox
*swc
= GNM_SOW_CHECKBOX (so
);
2661 if (go_str_compare (str
, swc
->label
) == 0)
2664 new_label
= g_strdup (str
);
2665 g_free (swc
->label
);
2666 swc
->label
= new_label
;
2668 for (list
= swc
->sow
.so
.realized_list
; list
; list
= list
->next
) {
2669 SheetObjectView
*view
= list
->data
;
2670 GocWidget
*item
= get_goc_widget (view
);
2671 gtk_button_set_label (GTK_BUTTON (item
->widget
), swc
->label
);
2676 sheet_widget_checkbox_draw_cairo (SheetObject
const *so
, cairo_t
*cr
,
2677 double width
, double height
)
2679 SheetWidgetCheckbox
const *swc
= GNM_SOW_CHECKBOX (so
);
2680 double halfheight
= height
/2;
2681 double dx
= 8., dxh
, pm
;
2684 pm
= MIN (height
- 2, width
- 12);
2690 cairo_set_line_width (cr
, 0.5);
2691 cairo_set_source_rgb(cr
, 1.0, 1.0, 1.0);
2693 cairo_new_path (cr
);
2694 cairo_move_to (cr
, dxh
, halfheight
- dxh
);
2695 cairo_rel_line_to (cr
, 0, dx
);
2696 cairo_rel_line_to (cr
, dx
, 0);
2697 cairo_rel_line_to (cr
, 0., -dx
);
2698 cairo_rel_line_to (cr
, -dx
, 0.);
2699 cairo_close_path (cr
);
2700 cairo_fill_preserve (cr
);
2701 cairo_set_source_rgb(cr
, 0.0, 0.0, 0.0);
2705 cairo_new_path (cr
);
2706 cairo_move_to (cr
, dxh
, halfheight
- dxh
);
2707 cairo_rel_line_to (cr
, dx
, dx
);
2708 cairo_rel_line_to (cr
, -dx
, 0.);
2709 cairo_rel_line_to (cr
, dx
, -dx
);
2710 cairo_rel_line_to (cr
, -dx
, 0.);
2711 cairo_close_path (cr
);
2712 cairo_set_line_join (cr
, CAIRO_LINE_JOIN_BEVEL
);
2716 cairo_move_to (cr
, 2 * dx
, halfheight
);
2718 pw
= width
- 2 * dx
;
2721 draw_cairo_text (cr
, swc
->label
, &pw
, &ph
, TRUE
, FALSE
, TRUE
, 0, TRUE
);
2723 cairo_new_path (cr
);
2728 SOW_MAKE_TYPE (checkbox
, Checkbox
,
2729 sheet_widget_checkbox_user_config
,
2730 sheet_widget_checkbox_set_sheet
,
2732 sheet_widget_checkbox_foreach_dep
,
2733 sheet_widget_checkbox_copy
,
2734 sheet_widget_checkbox_write_xml_sax
,
2735 sheet_widget_checkbox_prep_sax_parser
,
2736 sheet_widget_checkbox_get_property
,
2737 sheet_widget_checkbox_set_property
,
2738 sheet_widget_checkbox_draw_cairo
,
2740 g_object_class_install_property
2741 (object_class
, SOC_PROP_ACTIVE
,
2742 g_param_spec_boolean ("active", NULL
, NULL
,
2744 GSF_PARAM_STATIC
| G_PARAM_READWRITE
));
2745 g_object_class_install_property
2746 (object_class
, SOC_PROP_TEXT
,
2747 g_param_spec_string ("text", NULL
, NULL
, NULL
,
2748 GSF_PARAM_STATIC
| G_PARAM_READWRITE
));
2749 g_object_class_install_property
2750 (object_class
, SOC_PROP_MARKUP
,
2751 g_param_spec_boxed ("markup", NULL
, NULL
, PANGO_TYPE_ATTR_LIST
,
2752 GSF_PARAM_STATIC
| G_PARAM_READWRITE
));
2755 /****************************************************************************/
2756 typedef SheetWidgetCheckbox SheetWidgetToggleButton
;
2757 typedef SheetWidgetCheckboxClass SheetWidgetToggleButtonClass
;
2759 sheet_widget_toggle_button_create_widget (SheetObjectWidget
*sow
)
2761 SheetWidgetCheckbox
*swc
= GNM_SOW_CHECKBOX (sow
);
2762 GtkWidget
*button
= gtk_toggle_button_new_with_label (swc
->label
);
2763 gtk_widget_set_can_focus (button
, FALSE
);
2764 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button
), swc
->value
);
2765 g_signal_connect (G_OBJECT (button
),
2767 G_CALLBACK (cb_checkbox_toggled
), swc
);
2771 sheet_widget_toggle_button_class_init (SheetObjectWidgetClass
*sow_class
)
2773 sow_class
->create_widget
= &sheet_widget_toggle_button_create_widget
;
2776 GSF_CLASS (SheetWidgetToggleButton
, sheet_widget_toggle_button
,
2777 &sheet_widget_toggle_button_class_init
, NULL
,
2778 GNM_SOW_CHECKBOX_TYPE
)
2780 /****************************************************************************/
2782 #define GNM_SOW_RADIO_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNM_SOW_RADIO_BUTTON_TYPE, SheetWidgetRadioButton))
2783 #define DEP_TO_RADIO_BUTTON(d_ptr) (SheetWidgetRadioButton *)(((char *)d_ptr) - G_STRUCT_OFFSET(SheetWidgetRadioButton, dep))
2786 SheetObjectWidget sow
;
2788 gboolean being_updated
;
2793 } SheetWidgetRadioButton
;
2794 typedef SheetObjectWidgetClass SheetWidgetRadioButtonClass
;
2805 sheet_widget_radio_button_set_active (SheetWidgetRadioButton
*swrb
,
2810 if (swrb
->active
== active
)
2812 swrb
->active
= active
;
2814 swrb
->being_updated
= TRUE
;
2816 for (ptr
= swrb
->sow
.so
.realized_list
; ptr
!= NULL
; ptr
= ptr
->next
) {
2817 SheetObjectView
*view
= ptr
->data
;
2818 GocWidget
*item
= get_goc_widget (view
);
2819 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item
->widget
),
2823 g_object_notify (G_OBJECT (swrb
), "active");
2825 swrb
->being_updated
= FALSE
;
2830 sheet_widget_radio_button_get_property (GObject
*obj
, guint param_id
,
2831 GValue
*value
, GParamSpec
*pspec
)
2833 SheetWidgetRadioButton
*swrb
= GNM_SOW_RADIO_BUTTON (obj
);
2836 case SOR_PROP_ACTIVE
:
2837 g_value_set_boolean (value
, swrb
->active
);
2840 g_value_set_string (value
, swrb
->label
);
2842 case SOR_PROP_MARKUP
:
2843 g_value_set_boxed (value
, NULL
); /* swrb->markup */
2845 case SOR_PROP_VALUE
:
2846 g_value_set_boxed (value
, swrb
->value
);
2849 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj
, param_id
, pspec
);
2855 sheet_widget_radio_button_set_property (GObject
*obj
, guint param_id
,
2856 GValue
const *value
, GParamSpec
*pspec
)
2858 SheetWidgetRadioButton
*swrb
= GNM_SOW_RADIO_BUTTON (obj
);
2861 case SOR_PROP_ACTIVE
:
2862 sheet_widget_radio_button_set_active (swrb
,
2863 g_value_get_boolean (value
));
2866 sheet_widget_radio_button_set_label (GNM_SO (swrb
),
2867 g_value_get_string (value
));
2869 case SOR_PROP_MARKUP
:
2871 sheet_widget_radio_button_set_markup (GNM_SO (swrb
),
2872 g_value_peek_pointer (value
));
2875 case SOR_PROP_VALUE
:
2876 sheet_widget_radio_button_set_value (GNM_SO (swrb
),
2877 g_value_get_boxed (value
));
2880 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj
, param_id
, pspec
);
2886 sheet_widget_radio_button_get_value (SheetObject
*so
)
2888 SheetWidgetRadioButton
*swrb
;
2890 g_return_val_if_fail (GNM_IS_SOW_RADIO_BUTTON (so
), NULL
);
2892 swrb
= GNM_SOW_RADIO_BUTTON (so
);
2897 sheet_widget_radio_button_set_value (SheetObject
*so
, GnmValue
const *val
)
2899 SheetWidgetRadioButton
*swrb
= GNM_SOW_RADIO_BUTTON (so
);
2901 value_release (swrb
->value
);
2902 swrb
->value
= value_dup (val
);
2906 radio_button_eval (GnmDependent
*dep
)
2910 SheetWidgetRadioButton
*swrb
= DEP_TO_RADIO_BUTTON (dep
);
2912 v
= gnm_expr_top_eval (dep
->texpr
, eval_pos_init_dep (&pos
, dep
),
2913 GNM_EXPR_EVAL_SCALAR_NON_EMPTY
);
2914 if (v
&& swrb
->value
) {
2915 gboolean active
= value_equal (swrb
->value
, v
);
2916 sheet_widget_radio_button_set_active (swrb
, active
);
2922 radio_button_debug_name (GnmDependent
const *dep
, GString
*target
)
2924 g_string_append_printf (target
, "RadioButton%p", (void *)dep
);
2927 static DEPENDENT_MAKE_TYPE (radio_button
, NULL
)
2930 sheet_widget_radio_button_init_full (SheetWidgetRadioButton
*swrb
,
2931 GnmCellRef
const *ref
,
2933 GnmValue
const *value
,
2936 g_return_if_fail (swrb
!= NULL
);
2938 swrb
->being_updated
= FALSE
;
2939 swrb
->label
= g_strdup (label
? label
: _("RadioButton"));
2940 swrb
->value
= value
? value_dup (value
) : value_new_empty ();
2941 swrb
->active
= active
;
2943 swrb
->dep
.sheet
= NULL
;
2944 swrb
->dep
.flags
= radio_button_get_dep_type ();
2945 swrb
->dep
.texpr
= (ref
!= NULL
)
2946 ? gnm_expr_top_new (gnm_expr_new_cellref (ref
))
2951 sheet_widget_radio_button_init (SheetWidgetRadioButton
*swrb
)
2953 sheet_widget_radio_button_init_full (swrb
, NULL
, NULL
, NULL
, TRUE
);
2957 sheet_widget_radio_button_finalize (GObject
*obj
)
2959 SheetWidgetRadioButton
*swrb
= GNM_SOW_RADIO_BUTTON (obj
);
2961 g_return_if_fail (swrb
!= NULL
);
2963 g_free (swrb
->label
);
2965 value_release (swrb
->value
);
2968 dependent_set_expr (&swrb
->dep
, NULL
);
2970 sheet_object_widget_class
->finalize (obj
);
2974 sheet_widget_radio_button_toggled (GtkToggleButton
*button
,
2975 SheetWidgetRadioButton
*swrb
)
2979 if (swrb
->being_updated
)
2981 swrb
->active
= gtk_toggle_button_get_active (button
);
2983 if (so_get_ref (GNM_SO (swrb
), &ref
, TRUE
) != NULL
) {
2984 cmd_so_set_value (widget_wbc (GTK_WIDGET (button
)),
2985 /* FIXME: This text sucks: */
2986 _("Clicking radiobutton"),
2987 &ref
, value_dup (swrb
->value
),
2988 sheet_object_get_sheet (GNM_SO (swrb
)));
2993 sheet_widget_radio_button_create_widget (SheetObjectWidget
*sow
)
2995 SheetWidgetRadioButton
*swrb
= GNM_SOW_RADIO_BUTTON (sow
);
2996 GtkWidget
*w
= g_object_new (GNM_TYPE_RADIO_BUTTON
,
2997 "label", swrb
->label
,
3000 gtk_widget_set_can_focus (w
, FALSE
);
3002 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w
), swrb
->active
);
3004 g_signal_connect (G_OBJECT (w
),
3006 G_CALLBACK (sheet_widget_radio_button_toggled
), sow
);
3011 sheet_widget_radio_button_copy (SheetObject
*dst
, SheetObject
const *src
)
3013 SheetWidgetRadioButton
const *src_swrb
= GNM_SOW_RADIO_BUTTON (src
);
3014 SheetWidgetRadioButton
*dst_swrb
= GNM_SOW_RADIO_BUTTON (dst
);
3017 sheet_widget_radio_button_init_full (dst_swrb
,
3018 so_get_ref (src
, &ref
, FALSE
),
3025 sheet_widget_radio_button_set_sheet (SheetObject
*so
, Sheet
*sheet
)
3027 SheetWidgetRadioButton
*swrb
= GNM_SOW_RADIO_BUTTON (so
);
3029 dependent_set_sheet (&swrb
->dep
, sheet
);
3035 sheet_widget_radio_button_foreach_dep (SheetObject
*so
,
3036 SheetObjectForeachDepFunc func
,
3039 SheetWidgetRadioButton
*swrb
= GNM_SOW_RADIO_BUTTON (so
);
3040 func (&swrb
->dep
, so
, user
);
3044 sheet_widget_radio_button_write_xml_sax (SheetObject
const *so
,
3046 GnmConventions
const *convs
)
3048 SheetWidgetRadioButton
const *swrb
= GNM_SOW_RADIO_BUTTON (so
);
3049 GString
*valstr
= g_string_new (NULL
);
3051 value_get_as_gstring (swrb
->value
, valstr
, convs
);
3053 gsf_xml_out_add_cstr (output
, "Label", swrb
->label
);
3054 gsf_xml_out_add_cstr (output
, "Value", valstr
->str
);
3055 gsf_xml_out_add_int (output
, "ValueType", swrb
->value
->v_any
.type
);
3056 gsf_xml_out_add_int (output
, "Active", swrb
->active
);
3057 sax_write_dep (output
, &swrb
->dep
, "Input", convs
);
3059 g_string_free (valstr
, TRUE
);
3063 sheet_widget_radio_button_prep_sax_parser (SheetObject
*so
, GsfXMLIn
*xin
,
3064 xmlChar
const **attrs
,
3065 GnmConventions
const *convs
)
3067 SheetWidgetRadioButton
*swrb
= GNM_SOW_RADIO_BUTTON (so
);
3068 const char *valstr
= NULL
;
3071 for (; attrs
!= NULL
&& attrs
[0] && attrs
[1] ; attrs
+= 2) {
3072 if (attr_eq (attrs
[0], "Label")) {
3073 g_free (swrb
->label
);
3074 swrb
->label
= g_strdup (CXML2C (attrs
[1]));
3075 } else if (attr_eq (attrs
[0], "Value")) {
3076 valstr
= CXML2C (attrs
[1]);
3077 } else if (gnm_xml_attr_bool (attrs
, "Active", &swrb
->active
) ||
3078 gnm_xml_attr_int (attrs
, "ValueType", &value_type
) ||
3079 sax_read_dep (attrs
, "Input", &swrb
->dep
, xin
, convs
))
3083 value_release (swrb
->value
);
3086 swrb
->value
= value_type
3087 ? value_new_from_string (value_type
, valstr
, NULL
, FALSE
)
3088 : format_match (valstr
, NULL
, NULL
);
3091 swrb
->value
= value_new_empty ();
3095 sheet_widget_radio_button_set_link (SheetObject
*so
, GnmExprTop
const *texpr
)
3097 SheetWidgetRadioButton
*swrb
= GNM_SOW_RADIO_BUTTON (so
);
3098 dependent_set_expr (&swrb
->dep
, texpr
);
3099 if (texpr
&& swrb
->dep
.sheet
)
3100 dependent_link (&swrb
->dep
);
3104 sheet_widget_radio_button_get_link (SheetObject
*so
)
3106 SheetWidgetRadioButton
*swrb
= GNM_SOW_RADIO_BUTTON (so
);
3107 GnmExprTop
const *texpr
= swrb
->dep
.texpr
;
3110 gnm_expr_top_ref (texpr
);
3116 sheet_widget_radio_button_set_label (SheetObject
*so
, char const *str
)
3119 SheetWidgetRadioButton
*swrb
= GNM_SOW_RADIO_BUTTON (so
);
3122 if (go_str_compare (str
, swrb
->label
) == 0)
3125 new_label
= g_strdup (str
);
3126 g_free (swrb
->label
);
3127 swrb
->label
= new_label
;
3129 for (list
= swrb
->sow
.so
.realized_list
; list
; list
= list
->next
) {
3130 SheetObjectView
*view
= list
->data
;
3131 GocWidget
*item
= get_goc_widget (view
);
3132 gtk_button_set_label (GTK_BUTTON (item
->widget
), swrb
->label
);
3139 GnmExprEntry
*expression
;
3140 GtkWidget
*label
, *value
;
3143 GnmValue
*old_value
;
3144 GtkWidget
*old_focus
;
3147 SheetWidgetRadioButton
*swrb
;
3149 } RadioButtonConfigState
;
3152 cb_radio_button_set_focus (G_GNUC_UNUSED GtkWidget
*window
, GtkWidget
*focus_widget
,
3153 RadioButtonConfigState
*state
)
3157 /* Note: half of the set-focus action is handle by the default
3158 * callback installed by wbc_gtk_attach_guru */
3160 ofp
= state
->old_focus
3161 ? gtk_widget_get_parent (state
->old_focus
)
3164 /* Force an update of the content in case it needs tweaking (eg make it
3166 if (ofp
&& GNM_EXPR_ENTRY_IS (ofp
)) {
3168 GnmExprTop
const *texpr
= gnm_expr_entry_parse (
3169 GNM_EXPR_ENTRY (ofp
),
3170 parse_pos_init_sheet (&pp
, state
->sheet
),
3171 NULL
, FALSE
, GNM_EXPR_PARSE_DEFAULT
);
3173 gnm_expr_top_unref (texpr
);
3175 state
->old_focus
= focus_widget
;
3179 cb_radio_button_config_destroy (RadioButtonConfigState
*state
)
3181 g_return_if_fail (state
!= NULL
);
3183 g_free (state
->old_label
);
3184 state
->old_label
= NULL
;
3186 value_release (state
->old_value
);
3187 state
->old_value
= NULL
;
3189 state
->dialog
= NULL
;
3195 so_parse_value (SheetObject
*so
, const char *s
)
3197 Sheet
*sheet
= so
->sheet
;
3198 return format_match (s
, NULL
, sheet_date_conv (sheet
));
3202 cb_radio_button_config_ok_clicked (G_GNUC_UNUSED GtkWidget
*button
, RadioButtonConfigState
*state
)
3204 SheetObject
*so
= GNM_SO (state
->swrb
);
3206 GnmExprTop
const *texpr
= gnm_expr_entry_parse
3208 parse_pos_init_sheet (&pp
, so
->sheet
),
3209 NULL
, FALSE
, GNM_EXPR_PARSE_DEFAULT
);
3210 gchar
const *text
= gtk_entry_get_text (GTK_ENTRY (state
->label
));
3211 gchar
const *val
= gtk_entry_get_text (GTK_ENTRY (state
->value
));
3212 GnmValue
*new_val
= so_parse_value (so
, val
);
3214 cmd_so_set_radio_button (GNM_WBC (state
->wbcg
), so
,
3216 g_strdup (state
->old_label
), g_strdup (text
),
3217 value_dup (state
->old_value
), new_val
);
3219 gtk_widget_destroy (state
->dialog
);
3223 cb_radio_button_config_cancel_clicked (G_GNUC_UNUSED GtkWidget
*button
, RadioButtonConfigState
*state
)
3225 sheet_widget_radio_button_set_label (GNM_SO (state
->swrb
),
3227 sheet_widget_radio_button_set_value (GNM_SO (state
->swrb
),
3229 gtk_widget_destroy (state
->dialog
);
3233 cb_radio_button_label_changed (GtkEntry
*entry
, RadioButtonConfigState
*state
)
3235 sheet_widget_radio_button_set_label (GNM_SO (state
->swrb
),
3236 gtk_entry_get_text (entry
));
3240 cb_radio_button_value_changed (GtkEntry
*entry
, RadioButtonConfigState
*state
)
3242 const char *text
= gtk_entry_get_text (entry
);
3243 SheetObject
*so
= GNM_SO (state
->swrb
);
3244 GnmValue
*val
= so_parse_value (so
, text
);
3246 sheet_widget_radio_button_set_value (so
, val
);
3247 value_release (val
);
3251 sheet_widget_radio_button_user_config (SheetObject
*so
, SheetControl
*sc
)
3253 SheetWidgetRadioButton
*swrb
= GNM_SOW_RADIO_BUTTON (so
);
3254 WBCGtk
*wbcg
= scg_wbcg (GNM_SCG (sc
));
3255 RadioButtonConfigState
*state
;
3260 g_return_if_fail (swrb
!= NULL
);
3262 /* Only pop up one copy per workbook */
3263 if (gnm_dialog_raise_if_exists (wbcg
, SHEET_OBJECT_CONFIG_KEY
))
3266 gui
= gnm_gtk_builder_load ("res:ui/so-radiobutton.ui", NULL
, GO_CMD_CONTEXT (wbcg
));
3269 state
= g_new (RadioButtonConfigState
, 1);
3272 state
->sheet
= sc_sheet (sc
);
3273 state
->old_focus
= NULL
;
3274 state
->old_label
= g_strdup (swrb
->label
);
3275 state
->old_value
= value_dup (swrb
->value
);
3276 state
->dialog
= go_gtk_builder_get_widget (gui
, "SO-Radiobutton");
3278 grid
= go_gtk_builder_get_widget (gui
, "main-grid");
3280 state
->expression
= gnm_expr_entry_new (wbcg
, TRUE
);
3281 gnm_expr_entry_set_flags (state
->expression
,
3282 GNM_EE_FORCE_ABS_REF
| GNM_EE_SHEET_OPTIONAL
| GNM_EE_SINGLE_RANGE
,
3284 gnm_expr_entry_load_from_dep (state
->expression
, &swrb
->dep
);
3285 go_atk_setup_label (go_gtk_builder_get_widget (gui
, "label_linkto"),
3286 GTK_WIDGET (state
->expression
));
3287 gtk_grid_attach (GTK_GRID (grid
),
3288 GTK_WIDGET (state
->expression
), 1, 0, 1, 1);
3289 gtk_widget_show (GTK_WIDGET (state
->expression
));
3291 state
->label
= go_gtk_builder_get_widget (gui
, "label_entry");
3292 gtk_entry_set_text (GTK_ENTRY (state
->label
), swrb
->label
);
3293 gtk_editable_select_region (GTK_EDITABLE(state
->label
), 0, -1);
3294 state
->value
= go_gtk_builder_get_widget (gui
, "value_entry");
3296 valstr
= g_string_new (NULL
);
3297 value_get_as_gstring (swrb
->value
, valstr
, so
->sheet
->convs
);
3298 gtk_entry_set_text (GTK_ENTRY (state
->value
), valstr
->str
);
3299 g_string_free (valstr
, TRUE
);
3301 gnm_editable_enters (GTK_WINDOW (state
->dialog
),
3302 GTK_WIDGET (state
->expression
));
3303 gnm_editable_enters (GTK_WINDOW (state
->dialog
),
3304 GTK_WIDGET (state
->label
));
3305 gnm_editable_enters (GTK_WINDOW (state
->dialog
),
3306 GTK_WIDGET (state
->value
));
3308 g_signal_connect (G_OBJECT (state
->label
),
3310 G_CALLBACK (cb_radio_button_label_changed
), state
);
3311 g_signal_connect (G_OBJECT (state
->value
),
3313 G_CALLBACK (cb_radio_button_value_changed
), state
);
3314 g_signal_connect (G_OBJECT (go_gtk_builder_get_widget (gui
, "ok_button")),
3316 G_CALLBACK (cb_radio_button_config_ok_clicked
), state
);
3317 g_signal_connect (G_OBJECT (go_gtk_builder_get_widget (gui
, "cancel_button")),
3319 G_CALLBACK (cb_radio_button_config_cancel_clicked
), state
);
3321 gnm_init_help_button (
3322 go_gtk_builder_get_widget (gui
, "help_button"),
3323 GNUMERIC_HELP_LINK_SO_RADIO_BUTTON
);
3325 gnm_keyed_dialog (state
->wbcg
, GTK_WINDOW (state
->dialog
),
3326 SHEET_OBJECT_CONFIG_KEY
);
3328 wbc_gtk_attach_guru (state
->wbcg
, state
->dialog
);
3329 g_object_set_data_full (G_OBJECT (state
->dialog
),
3330 "state", state
, (GDestroyNotify
) cb_radio_button_config_destroy
);
3331 g_object_unref (gui
);
3333 /* Note: half of the set-focus action is handle by the default */
3334 /* callback installed by wbc_gtk_attach_guru */
3335 g_signal_connect (G_OBJECT (state
->dialog
), "set-focus",
3336 G_CALLBACK (cb_radio_button_set_focus
), state
);
3338 gtk_widget_show (state
->dialog
);
3342 sheet_widget_radio_button_draw_cairo (SheetObject
const *so
, cairo_t
*cr
,
3343 G_GNUC_UNUSED
double width
, double height
)
3345 SheetWidgetRadioButton
const *swr
= GNM_SOW_RADIO_BUTTON (so
);
3346 double halfheight
= height
/2;
3347 double dx
= 8., dxh
, pm
;
3350 pm
= MIN (height
- 2, width
- 12);
3356 cairo_set_line_width (cr
, 0.5);
3357 cairo_set_source_rgb(cr
, 1.0, 1.0, 1.0);
3359 cairo_new_path (cr
);
3360 cairo_move_to (cr
, dxh
+ dx
, halfheight
);
3361 cairo_arc (cr
, dx
, halfheight
, dxh
, 0., 2*M_PI
);
3362 cairo_close_path (cr
);
3363 cairo_fill_preserve (cr
);
3364 cairo_set_source_rgb(cr
, 0.0, 0.0, 0.0);
3368 cairo_new_path (cr
);
3369 cairo_move_to (cr
, dx
+ dxh
/2 + 0.5, halfheight
);
3370 cairo_arc (cr
, dx
, halfheight
, dxh
/2 + 0.5, 0., 2*M_PI
);
3371 cairo_close_path (cr
);
3375 cairo_move_to (cr
, 2 * dx
, halfheight
);
3377 pw
= width
- 2 * dx
;
3380 draw_cairo_text (cr
, swr
->label
, &pw
, &ph
, TRUE
, FALSE
, TRUE
, 0, TRUE
);
3382 cairo_new_path (cr
);
3386 SOW_MAKE_TYPE (radio_button
, RadioButton
,
3387 sheet_widget_radio_button_user_config
,
3388 sheet_widget_radio_button_set_sheet
,
3390 sheet_widget_radio_button_foreach_dep
,
3391 sheet_widget_radio_button_copy
,
3392 sheet_widget_radio_button_write_xml_sax
,
3393 sheet_widget_radio_button_prep_sax_parser
,
3394 sheet_widget_radio_button_get_property
,
3395 sheet_widget_radio_button_set_property
,
3396 sheet_widget_radio_button_draw_cairo
,
3398 g_object_class_install_property
3399 (object_class
, SOR_PROP_ACTIVE
,
3400 g_param_spec_boolean ("active", NULL
, NULL
,
3402 GSF_PARAM_STATIC
| G_PARAM_READWRITE
));
3403 g_object_class_install_property
3404 (object_class
, SOR_PROP_TEXT
,
3405 g_param_spec_string ("text", NULL
, NULL
, NULL
,
3406 GSF_PARAM_STATIC
| G_PARAM_READWRITE
));
3407 g_object_class_install_property
3408 (object_class
, SOR_PROP_MARKUP
,
3409 g_param_spec_boxed ("markup", NULL
, NULL
, PANGO_TYPE_ATTR_LIST
,
3410 GSF_PARAM_STATIC
| G_PARAM_READWRITE
));
3411 g_object_class_install_property
3412 (object_class
, SOR_PROP_VALUE
,
3413 g_param_spec_boxed ("value", NULL
, NULL
,
3414 gnm_value_get_type (),
3415 GSF_PARAM_STATIC
| G_PARAM_READWRITE
));
3418 /****************************************************************************/
3420 #define GNM_SOW_LIST_BASE_TYPE (sheet_widget_list_base_get_type ())
3421 #define GNM_SOW_LIST_BASE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNM_SOW_LIST_BASE_TYPE, SheetWidgetListBase))
3422 #define DEP_TO_LIST_BASE_CONTENT(d_ptr) (SheetWidgetListBase *)(((char *)d_ptr) - G_STRUCT_OFFSET(SheetWidgetListBase, content_dep))
3423 #define DEP_TO_LIST_BASE_OUTPUT(d_ptr) (SheetWidgetListBase *)(((char *)d_ptr) - G_STRUCT_OFFSET(SheetWidgetListBase, output_dep))
3426 SheetObjectWidget sow
;
3428 GnmDependent content_dep
; /* content of the list */
3429 GnmDependent output_dep
; /* selected element */
3431 GtkTreeModel
*model
;
3433 gboolean result_as_index
;
3434 } SheetWidgetListBase
;
3436 SheetObjectWidgetClass base
;
3438 void (*model_changed
) (SheetWidgetListBase
*list
);
3439 void (*selection_changed
) (SheetWidgetListBase
*list
);
3440 } SheetWidgetListBaseClass
;
3443 LIST_BASE_MODEL_CHANGED
,
3444 LIST_BASE_SELECTION_CHANGED
,
3445 LIST_BASE_LAST_SIGNAL
3448 static guint list_base_signals
[LIST_BASE_LAST_SIGNAL
] = { 0 };
3449 static GType
sheet_widget_list_base_get_type (void);
3452 sheet_widget_list_base_set_selection (SheetWidgetListBase
*swl
, int selection
,
3453 WorkbookControl
*wbc
)
3457 if (selection
>= 0 && swl
->model
!= NULL
) {
3458 int n
= gtk_tree_model_iter_n_children (swl
->model
, NULL
);
3464 if (swl
->selection
!= selection
) {
3465 swl
->selection
= selection
;
3467 so_get_ref (GNM_SO (swl
), &ref
, TRUE
) != NULL
) {
3469 if (swl
->result_as_index
)
3470 v
= value_new_int (swl
->selection
);
3471 else if (selection
!= 0) {
3474 gtk_tree_model_iter_nth_child
3475 (swl
->model
, &iter
, NULL
, selection
- 1);
3476 gtk_tree_model_get (swl
->model
, &iter
,
3478 v
= value_new_string_nocopy (content
);
3480 v
= value_new_string ("");
3481 cmd_so_set_value (wbc
, _("Clicking in list"), &ref
, v
,
3482 sheet_object_get_sheet (GNM_SO (swl
)));
3484 g_signal_emit (G_OBJECT (swl
),
3485 list_base_signals
[LIST_BASE_SELECTION_CHANGED
], 0);
3490 sheet_widget_list_base_set_selection_value (SheetWidgetListBase
*swl
, GnmValue
*v
)
3493 int selection
= 0, i
= 1;
3495 if (swl
->model
!= NULL
&& gtk_tree_model_get_iter_first (swl
->model
, &iter
)) {
3496 char *str
= value_get_as_string (v
);
3500 gtk_tree_model_get (swl
->model
, &iter
,
3502 match
= 0 == g_ascii_strcasecmp (str
, content
);
3509 } while (gtk_tree_model_iter_next (swl
->model
, &iter
));
3513 if (swl
->selection
!= selection
) {
3514 swl
->selection
= selection
;
3515 g_signal_emit (G_OBJECT (swl
),
3516 list_base_signals
[LIST_BASE_SELECTION_CHANGED
], 0);
3521 list_output_eval (GnmDependent
*dep
)
3524 GnmValue
*v
= gnm_expr_top_eval (dep
->texpr
,
3525 eval_pos_init_dep (&pos
, dep
),
3526 GNM_EXPR_EVAL_SCALAR_NON_EMPTY
);
3527 SheetWidgetListBase
*swl
= DEP_TO_LIST_BASE_OUTPUT (dep
);
3529 if (swl
->result_as_index
)
3530 sheet_widget_list_base_set_selection
3531 (swl
, floor (value_get_as_float (v
)), NULL
);
3533 sheet_widget_list_base_set_selection_value (swl
, v
);
3538 list_output_debug_name (GnmDependent
const *dep
, GString
*target
)
3540 g_string_append_printf (target
, "ListOutput%p", (void *)dep
);
3543 static DEPENDENT_MAKE_TYPE (list_output
, NULL
)
3547 cb_collect (GnmValueIter
const *iter
, GtkListStore
*model
)
3549 GtkTreeIter list_iter
;
3551 gtk_list_store_append (model
, &list_iter
);
3552 if (NULL
!= iter
->v
) {
3553 GOFormat
const *fmt
= (NULL
!= iter
->cell_iter
)
3554 ? gnm_cell_get_format (iter
->cell_iter
->cell
) : NULL
;
3555 char *label
= format_value (fmt
, iter
->v
, -1, NULL
);
3556 gtk_list_store_set (model
, &list_iter
, 0, label
, -1);
3559 gtk_list_store_set (model
, &list_iter
, 0, "", -1);
3564 list_content_eval (GnmDependent
*dep
)
3566 SheetWidgetListBase
*swl
= DEP_TO_LIST_BASE_CONTENT (dep
);
3569 GtkListStore
*model
;
3571 if (dep
->texpr
!= NULL
) {
3572 v
= gnm_expr_top_eval (dep
->texpr
,
3573 eval_pos_init_dep (&ep
, dep
),
3574 GNM_EXPR_EVAL_PERMIT_NON_SCALAR
|
3575 GNM_EXPR_EVAL_PERMIT_EMPTY
);
3577 model
= gtk_list_store_new (1, G_TYPE_STRING
);
3579 value_area_foreach (v
, &ep
, CELL_ITER_ALL
,
3580 (GnmValueIterFunc
) cb_collect
, model
);
3584 if (NULL
!= swl
->model
)
3585 g_object_unref (swl
->model
);
3586 swl
->model
= GTK_TREE_MODEL (model
);
3587 g_signal_emit (G_OBJECT (swl
), list_base_signals
[LIST_BASE_MODEL_CHANGED
], 0);
3591 list_content_debug_name (GnmDependent
const *dep
, GString
*target
)
3593 g_string_append_printf (target
, "ListContent%p", (void *)dep
);
3596 static DEPENDENT_MAKE_TYPE (list_content
, NULL
)
3601 sheet_widget_list_base_init (SheetObjectWidget
*sow
)
3603 SheetWidgetListBase
*swl
= GNM_SOW_LIST_BASE (sow
);
3604 SheetObject
*so
= GNM_SO (sow
);
3606 so
->flags
&= ~SHEET_OBJECT_PRINT
;
3608 swl
->content_dep
.sheet
= NULL
;
3609 swl
->content_dep
.flags
= list_content_get_dep_type ();
3610 swl
->content_dep
.texpr
= NULL
;
3612 swl
->output_dep
.sheet
= NULL
;
3613 swl
->output_dep
.flags
= list_output_get_dep_type ();
3614 swl
->output_dep
.texpr
= NULL
;
3618 swl
->result_as_index
= TRUE
;
3622 sheet_widget_list_base_finalize (GObject
*obj
)
3624 SheetWidgetListBase
*swl
= GNM_SOW_LIST_BASE (obj
);
3625 dependent_set_expr (&swl
->content_dep
, NULL
);
3626 dependent_set_expr (&swl
->output_dep
, NULL
);
3627 if (swl
->model
!= NULL
) {
3628 g_object_unref (swl
->model
);
3631 sheet_object_widget_class
->finalize (obj
);
3635 sheet_widget_list_base_user_config (SheetObject
*so
, SheetControl
*sc
)
3637 dialog_so_list (scg_wbcg (GNM_SCG (sc
)), G_OBJECT (so
));
3640 sheet_widget_list_base_set_sheet (SheetObject
*so
, Sheet
*sheet
)
3642 SheetWidgetListBase
*swl
= GNM_SOW_LIST_BASE (so
);
3644 g_return_val_if_fail (swl
!= NULL
, TRUE
);
3645 g_return_val_if_fail (swl
->content_dep
.sheet
== NULL
, TRUE
);
3646 g_return_val_if_fail (swl
->output_dep
.sheet
== NULL
, TRUE
);
3648 dependent_set_sheet (&swl
->content_dep
, sheet
);
3649 dependent_set_sheet (&swl
->output_dep
, sheet
);
3651 list_content_eval (&swl
->content_dep
); /* populate the list */
3657 sheet_widget_list_base_foreach_dep (SheetObject
*so
,
3658 SheetObjectForeachDepFunc func
,
3661 SheetWidgetListBase
*swl
= GNM_SOW_LIST_BASE (so
);
3662 func (&swl
->content_dep
, so
, user
);
3663 func (&swl
->output_dep
, so
, user
);
3667 sheet_widget_list_base_write_xml_sax (SheetObject
const *so
, GsfXMLOut
*output
,
3668 GnmConventions
const *convs
)
3670 SheetWidgetListBase
const *swl
= GNM_SOW_LIST_BASE (so
);
3671 sax_write_dep (output
, &swl
->content_dep
, "Content", convs
);
3672 sax_write_dep (output
, &swl
->output_dep
, "Output", convs
);
3673 gsf_xml_out_add_int (output
, "OutputAsIndex", swl
->result_as_index
? 1 : 0);
3677 sheet_widget_list_base_prep_sax_parser (SheetObject
*so
, GsfXMLIn
*xin
,
3678 xmlChar
const **attrs
,
3679 GnmConventions
const *convs
)
3681 SheetWidgetListBase
*swl
= GNM_SOW_LIST_BASE (so
);
3683 for (; attrs
!= NULL
&& attrs
[0] && attrs
[1] ; attrs
+= 2)
3684 if (sax_read_dep (attrs
, "Content", &swl
->content_dep
, xin
, convs
))
3686 else if (sax_read_dep (attrs
, "Output", &swl
->output_dep
, xin
, convs
))
3688 else if (gnm_xml_attr_bool (attrs
, "OutputAsIndex", &swl
->result_as_index
))
3693 sheet_widget_list_base_create_widget (G_GNUC_UNUSED SheetObjectWidget
*sow
)
3695 g_warning("ERROR: sheet_widget_list_base_create_widget SHOULD NEVER BE CALLED (but it has been)!\n");
3696 return gtk_frame_new ("invisiwidget(WARNING: I AM A BUG!)");
3699 SOW_MAKE_TYPE (list_base
, ListBase
,
3700 sheet_widget_list_base_user_config
,
3701 sheet_widget_list_base_set_sheet
,
3703 sheet_widget_list_base_foreach_dep
,
3705 sheet_widget_list_base_write_xml_sax
,
3706 sheet_widget_list_base_prep_sax_parser
,
3709 sheet_widget_draw_cairo
,
3711 list_base_signals
[LIST_BASE_MODEL_CHANGED
] = g_signal_new ("model-changed",
3712 GNM_SOW_LIST_BASE_TYPE
,
3714 G_STRUCT_OFFSET (SheetWidgetListBaseClass
, model_changed
),
3716 g_cclosure_marshal_VOID__VOID
,
3718 list_base_signals
[LIST_BASE_SELECTION_CHANGED
] = g_signal_new ("selection-changed",
3719 GNM_SOW_LIST_BASE_TYPE
,
3721 G_STRUCT_OFFSET (SheetWidgetListBaseClass
, selection_changed
),
3723 g_cclosure_marshal_VOID__VOID
,
3728 sheet_widget_list_base_set_links (SheetObject
*so
,
3729 GnmExprTop
const *output
,
3730 GnmExprTop
const *content
)
3732 SheetWidgetListBase
*swl
= GNM_SOW_LIST_BASE (so
);
3733 dependent_set_expr (&swl
->output_dep
, output
);
3734 if (output
&& swl
->output_dep
.sheet
)
3735 dependent_link (&swl
->output_dep
);
3736 dependent_set_expr (&swl
->content_dep
, content
);
3737 if (content
&& swl
->content_dep
.sheet
) {
3738 dependent_link (&swl
->content_dep
);
3739 list_content_eval (&swl
->content_dep
); /* populate the list */
3744 sheet_widget_list_base_get_result_link (SheetObject
const *so
)
3746 SheetWidgetListBase
*swl
= GNM_SOW_LIST_BASE (so
);
3747 GnmExprTop
const *texpr
= swl
->output_dep
.texpr
;
3750 gnm_expr_top_ref (texpr
);
3756 sheet_widget_list_base_get_content_link (SheetObject
const *so
)
3758 SheetWidgetListBase
*swl
= GNM_SOW_LIST_BASE (so
);
3759 GnmExprTop
const *texpr
= swl
->content_dep
.texpr
;
3762 gnm_expr_top_ref (texpr
);
3768 sheet_widget_list_base_result_type_is_index (SheetObject
const *so
)
3770 SheetWidgetListBase
*swl
= GNM_SOW_LIST_BASE (so
);
3772 return swl
->result_as_index
;
3776 sheet_widget_list_base_set_result_type (SheetObject
*so
, gboolean as_index
)
3778 SheetWidgetListBase
*swl
= GNM_SOW_LIST_BASE (so
);
3780 if (swl
->result_as_index
== as_index
)
3783 swl
->result_as_index
= as_index
;
3788 * sheet_widget_list_base_get_adjustment:
3791 * Note: allocates a new adjustment.
3792 * Returns: (transfer full): the newly created #GtkAdjustment.
3795 sheet_widget_list_base_get_adjustment (SheetObject
*so
)
3797 SheetWidgetListBase
*swl
= GNM_SOW_LIST_BASE (so
);
3800 g_return_val_if_fail (swl
, NULL
);
3802 adj
= (GtkAdjustment
*)gtk_adjustment_new
3805 1 + gtk_tree_model_iter_n_children (swl
->model
, NULL
),
3809 g_object_ref_sink (adj
);
3814 /****************************************************************************/
3816 #define GNM_SOW_LIST(o) (G_TYPE_CHECK_INSTANCE_CAST((o), GNM_SOW_LIST_TYPE, SheetWidgetList))
3818 typedef SheetWidgetListBase SheetWidgetList
;
3819 typedef SheetWidgetListBaseClass SheetWidgetListClass
;
3822 cb_list_selection_changed (SheetWidgetListBase
*swl
,
3823 GtkTreeSelection
*selection
)
3825 if (swl
->selection
> 0) {
3826 GtkTreePath
*path
= gtk_tree_path_new_from_indices (swl
->selection
-1, -1);
3827 gtk_tree_selection_select_path (selection
, path
);
3828 gtk_tree_path_free (path
);
3830 gtk_tree_selection_unselect_all (selection
);
3834 cb_list_model_changed (SheetWidgetListBase
*swl
, GtkTreeView
*list
)
3836 int old_selection
= swl
->selection
;
3837 swl
->selection
= -1;
3838 gtk_tree_view_set_model (GTK_TREE_VIEW (list
), swl
->model
);
3839 sheet_widget_list_base_set_selection (swl
, old_selection
, NULL
);
3842 cb_selection_changed (GtkTreeSelection
*selection
,
3843 SheetWidgetListBase
*swl
)
3845 GtkWidget
*view
= (GtkWidget
*)gtk_tree_selection_get_tree_view (selection
);
3846 GnmSimpleCanvas
*scanvas
= GNM_SIMPLE_CANVAS (gtk_widget_get_ancestor (view
, GNM_SIMPLE_CANVAS_TYPE
));
3847 GtkTreeModel
*model
;
3850 if (swl
->selection
!= -1) {
3851 if (gtk_tree_selection_get_selected (selection
, &model
, &iter
)) {
3852 GtkTreePath
*path
= gtk_tree_model_get_path (model
, &iter
);
3854 pos
= *gtk_tree_path_get_indices (path
) + 1;
3855 gtk_tree_path_free (path
);
3858 sheet_widget_list_base_set_selection
3859 (swl
, pos
, scg_wbc (scanvas
->scg
));
3864 sheet_widget_list_create_widget (SheetObjectWidget
*sow
)
3866 SheetWidgetListBase
*swl
= GNM_SOW_LIST_BASE (sow
);
3867 GtkTreeSelection
*selection
;
3869 GtkWidget
*list
= gtk_tree_view_new_with_model (swl
->model
);
3870 GtkWidget
*sw
= gtk_scrolled_window_new (
3871 gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (list
)),
3872 gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (list
)));
3873 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw
),
3874 GTK_POLICY_AUTOMATIC
,
3876 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (list
), FALSE
);
3877 gtk_tree_view_append_column (GTK_TREE_VIEW (list
),
3878 gtk_tree_view_column_new_with_attributes ("ID",
3879 gtk_cell_renderer_text_new (), "text", 0,
3882 gtk_container_add (GTK_CONTAINER (sw
), list
);
3884 g_signal_connect_object (G_OBJECT (swl
), "model-changed",
3885 G_CALLBACK (cb_list_model_changed
), list
, 0);
3887 selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (list
));
3888 if ((swl
->model
!= NULL
) && (swl
->selection
> 0) &&
3889 gtk_tree_model_iter_nth_child (swl
->model
, &iter
, NULL
, swl
->selection
- 1))
3890 gtk_tree_selection_select_iter (selection
, &iter
);
3891 g_signal_connect_object (G_OBJECT (swl
), "selection-changed",
3892 G_CALLBACK (cb_list_selection_changed
), selection
, 0);
3893 g_signal_connect (selection
, "changed",
3894 G_CALLBACK (cb_selection_changed
), swl
);
3899 sheet_widget_list_draw_cairo (SheetObject
const *so
, cairo_t
*cr
,
3900 double width
, double height
)
3902 SheetWidgetListBase
*swl
= GNM_SOW_LIST_BASE (so
);
3905 cairo_set_line_width (cr
, 0.5);
3906 cairo_set_source_rgb(cr
, 0, 0, 0);
3908 cairo_new_path (cr
);
3909 cairo_move_to (cr
, 0, 0);
3910 cairo_line_to (cr
, width
, 0);
3911 cairo_line_to (cr
, width
, height
);
3912 cairo_line_to (cr
, 0, height
);
3913 cairo_close_path (cr
);
3916 cairo_new_path (cr
);
3917 cairo_move_to (cr
, width
- 10, 0);
3918 cairo_rel_line_to (cr
, 0, height
);
3921 cairo_set_source_rgb(cr
, 0.5, 0.5, 0.5);
3923 cairo_new_path (cr
);
3924 cairo_move_to (cr
, width
- 5 -3, height
- 12);
3925 cairo_rel_line_to (cr
, 6, 0);
3926 cairo_rel_line_to (cr
, -3, 8);
3927 cairo_close_path (cr
);
3930 cairo_new_path (cr
);
3931 cairo_move_to (cr
, width
- 5 -3, 12);
3932 cairo_rel_line_to (cr
, 6, 0);
3933 cairo_rel_line_to (cr
, -3, -8);
3934 cairo_close_path (cr
);
3937 if (swl
->model
!= NULL
) {
3939 GString
*str
= g_string_new (NULL
);
3940 int twidth
= width
, theight
= height
;
3943 cairo_new_path (cr
);
3944 cairo_rectangle (cr
, 2, 1, width
- 2 - 12, height
- 2);
3946 if (gtk_tree_model_get_iter_first (swl
->model
, &iter
))
3948 char *astr
= NULL
, *newline
;
3949 gtk_tree_model_get (swl
->model
, &iter
, 0, &astr
, -1);
3950 while (NULL
!= (newline
= strchr (astr
, '\n')))
3952 g_string_append (str
, astr
);
3953 g_string_append_c (str
, '\n');
3955 } while (gtk_tree_model_iter_next (swl
->model
, &iter
));
3957 cairo_translate (cr
, 4., 2.);
3959 draw_cairo_text (cr
, str
->str
, &twidth
, &theight
, FALSE
, FALSE
, FALSE
,
3960 swl
->selection
, FALSE
);
3962 g_string_free (str
, TRUE
);
3965 cairo_new_path (cr
);
3970 sheet_widget_list_class_init (SheetObjectWidgetClass
*sow_class
)
3972 SheetObjectClass
*so_class
= GNM_SO_CLASS (sow_class
);
3974 so_class
->draw_cairo
= &sheet_widget_list_draw_cairo
;
3975 sow_class
->create_widget
= &sheet_widget_list_create_widget
;
3978 GSF_CLASS (SheetWidgetList
, sheet_widget_list
,
3979 &sheet_widget_list_class_init
, NULL
,
3980 GNM_SOW_LIST_BASE_TYPE
)
3982 /****************************************************************************/
3984 #define GNM_SOW_COMBO(o) (G_TYPE_CHECK_INSTANCE_CAST((o), GNM_SOW_COMBO_TYPE, SheetWidgetCombo))
3986 typedef SheetWidgetListBase SheetWidgetCombo
;
3987 typedef SheetWidgetListBaseClass SheetWidgetComboClass
;
3990 cb_combo_selection_changed (SheetWidgetListBase
*swl
,
3993 int pos
= swl
->selection
- 1;
3995 gtk_entry_set_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (combo
))), "");
3998 gtk_combo_box_set_active (combo
, pos
);
4002 cb_combo_model_changed (SheetWidgetListBase
*swl
, GtkComboBox
*combo
)
4004 gtk_combo_box_set_model (GTK_COMBO_BOX (combo
), swl
->model
);
4006 /* we can not set this until we have a model,
4007 * but after that we can not reset it */
4008 if (gtk_combo_box_get_entry_text_column (GTK_COMBO_BOX (combo
)) < 0)
4009 gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX (combo
), 0);
4011 /* force entry to reload */
4012 cb_combo_selection_changed (swl
, combo
);
4016 cb_combo_changed (GtkComboBox
*combo
, SheetWidgetListBase
*swl
)
4018 int pos
= gtk_combo_box_get_active (combo
) + 1;
4019 sheet_widget_list_base_set_selection (swl
, pos
,
4020 widget_wbc (GTK_WIDGET (combo
)));
4024 sheet_widget_combo_create_widget (SheetObjectWidget
*sow
)
4026 SheetWidgetListBase
*swl
= GNM_SOW_LIST_BASE (sow
);
4027 GtkWidget
*widget
= gtk_event_box_new (), *combo
;
4029 combo
= gtk_combo_box_new_with_entry ();
4030 gtk_widget_set_can_focus (gtk_bin_get_child (GTK_BIN (combo
)),
4032 if (swl
->model
!= NULL
)
4033 g_object_set (G_OBJECT (combo
),
4034 "model", swl
->model
,
4035 "entry-text-column", 0,
4036 "active", swl
->selection
- 1,
4039 g_signal_connect_object (G_OBJECT (swl
), "model-changed",
4040 G_CALLBACK (cb_combo_model_changed
), combo
, 0);
4041 g_signal_connect_object (G_OBJECT (swl
), "selection-changed",
4042 G_CALLBACK (cb_combo_selection_changed
), combo
, 0);
4043 g_signal_connect (G_OBJECT (combo
), "changed",
4044 G_CALLBACK (cb_combo_changed
), swl
);
4046 gtk_container_add (GTK_CONTAINER (widget
), combo
);
4047 gtk_event_box_set_visible_window (GTK_EVENT_BOX (widget
), FALSE
);
4052 sheet_widget_combo_draw_cairo (SheetObject
const *so
, cairo_t
*cr
,
4053 double width
, double height
)
4055 SheetWidgetListBase
*swl
= GNM_SOW_LIST_BASE (so
);
4056 double halfheight
= height
/2;
4059 cairo_set_line_width (cr
, 0.5);
4060 cairo_set_source_rgb(cr
, 0, 0, 0);
4062 cairo_new_path (cr
);
4063 cairo_move_to (cr
, 0, 0);
4064 cairo_line_to (cr
, width
, 0);
4065 cairo_line_to (cr
, width
, height
);
4066 cairo_line_to (cr
, 0, height
);
4067 cairo_close_path (cr
);
4070 cairo_new_path (cr
);
4071 cairo_move_to (cr
, width
- 10, 0);
4072 cairo_rel_line_to (cr
, 0, height
);
4075 cairo_set_source_rgb(cr
, 0.5, 0.5, 0.5);
4077 cairo_new_path (cr
);
4078 cairo_move_to (cr
, width
- 5 -3, halfheight
- 4);
4079 cairo_rel_line_to (cr
, 6, 0);
4080 cairo_rel_line_to (cr
, -3, 8);
4081 cairo_close_path (cr
);
4084 cairo_set_source_rgb(cr
, 0, 0, 0);
4085 cairo_move_to (cr
, 4., halfheight
);
4087 if (swl
->model
!= NULL
) {
4089 if (gtk_tree_model_iter_nth_child (swl
->model
, &iter
, NULL
,
4090 swl
->selection
- 1)) {
4092 gtk_tree_model_get (swl
->model
, &iter
, 0, &str
, -1);
4093 draw_cairo_text (cr
, str
, NULL
, NULL
, TRUE
, FALSE
, TRUE
, 0, FALSE
);
4098 cairo_new_path (cr
);
4103 sheet_widget_combo_class_init (SheetObjectWidgetClass
*sow_class
)
4105 SheetObjectClass
*so_class
= GNM_SO_CLASS (sow_class
);
4107 so_class
->draw_cairo
= &sheet_widget_combo_draw_cairo
;
4108 sow_class
->create_widget
= &sheet_widget_combo_create_widget
;
4111 GSF_CLASS (SheetWidgetCombo
, sheet_widget_combo
,
4112 &sheet_widget_combo_class_init
, NULL
,
4113 GNM_SOW_LIST_BASE_TYPE
)
4119 /**************************************************************************/
4122 * sheet_widget_init_clases:
4125 * Initilize the classes for the sheet-object-widgets. We need to initalize
4126 * them before we try loading a sheet that might contain sheet-object-widgets
4129 sheet_object_widget_register (void)
4132 GNM_SOW_BUTTON_TYPE
;
4133 GNM_SOW_SCROLLBAR_TYPE
;
4134 GNM_SOW_CHECKBOX_TYPE
;
4135 GNM_SOW_RADIO_BUTTON_TYPE
;
4138 GNM_SOW_SPIN_BUTTON_TYPE
;
4139 GNM_SOW_SLIDER_TYPE
;