Make graphs (and images) not resize with cells by default. [#684450]
[gnumeric.git] / src / dialogs / dialog-sheetobject-size.c
blobb7a980c576677e29753d2971fcd98d49e4d1feba
1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /**
3 * dialog-sheetobject-size.c:
5 * Author:
6 * Andreas J. Guelzow <aguelzow@pyrshep.ca>
8 * (c) Copyright 2009 Andreas J. Guelzow <aguelzow@pyrshep.ca>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include <gnumeric-config.h>
25 #include <glib/gi18n-lib.h>
26 #include <gnumeric.h>
27 #include <string.h>
28 #include "dialogs.h"
29 #include "help.h"
31 #include <gui-util.h>
32 #include <commands.h>
33 #include <workbook-control.h>
34 #include <workbook.h>
35 #include <wbc-gtk.h>
36 #include <sheet.h>
37 #include <sheet-view.h>
38 #include <application.h>
39 #include <workbook-cmd-format.h>
40 #include <sheet-object-widget.h>
41 #include <sheet-object-impl.h>
42 #include <sheet-control-gui.h>
43 #include <widgets/gnm-so-anchor-mode-chooser.h>
45 #include <gtk/gtk.h>
47 #define SO_SIZE_DIALOG_KEY "so-size-dialog"
49 typedef struct {
50 GtkBuilder *gui;
51 WBCGtk *wbcg;
52 Sheet *sheet;
53 SheetView *sv;
54 SheetControlGUI *scg;
55 GtkWidget *dialog;
56 GtkWidget *ok_button;
57 GtkWidget *apply_button;
58 GtkWidget *cancel_button;
59 GtkWidget *wpoints;
60 GtkSpinButton *wspin;
61 GtkWidget *hpoints;
62 GtkSpinButton *hspin;
63 GtkWidget *xpoints;
64 GtkSpinButton *xspin;
65 GtkWidget *ypoints;
66 GtkSpinButton *yspin;
67 GtkEntry *nameentry;
68 GtkWidget *print_check;
69 GnmSOAnchorModeChooser *modecombo;
71 SheetObject *so;
72 SheetObjectAnchor *old_anchor;
73 SheetObjectAnchor *active_anchor;
74 double coords[4];
75 gchar *old_name;
76 gboolean so_size_needs_restore;
77 gboolean so_pos_needs_restore;
78 gboolean so_name_changed;
79 gboolean so_print_check_changed;
80 gboolean so_mode_changed;
81 } SOSizeState;
83 static void
84 cb_dialog_so_size_value_changed_update_points (GtkSpinButton *spinbutton,
85 GtkLabel *points)
87 gint value = gtk_spin_button_get_value_as_int (spinbutton);
88 double size_points = value * 72./gnm_app_display_dpi_get (FALSE);
89 gchar *pts = g_strdup_printf ("%.2f",size_points);
90 gtk_label_set_text (points, pts);
91 g_free (pts);
94 static void
95 dialog_so_size_button_sensitivity (SOSizeState *state)
97 gboolean sensitive = state->so_size_needs_restore ||
98 state->so_pos_needs_restore ||
99 state->so_name_changed ||
100 state->so_print_check_changed ||
101 state->so_mode_changed;
102 gtk_widget_set_sensitive
103 (state->ok_button, sensitive);
104 gtk_widget_set_sensitive
105 (state->apply_button, sensitive);
108 static void
109 cb_dialog_so_size_destroy (SOSizeState *state)
111 if (state->so_size_needs_restore || state->so_pos_needs_restore)
112 sheet_object_set_anchor (state->so, state->old_anchor);
113 g_free (state->old_anchor);
114 g_free (state->active_anchor);
115 g_free (state->old_name);
116 if (state->so!= NULL)
117 g_object_unref (state->so);
118 if (state->gui != NULL)
119 g_object_unref (state->gui);
120 g_free (state);
123 static void
124 cb_dialog_so_size_cancel_clicked (G_GNUC_UNUSED GtkWidget *button,
125 SOSizeState *state)
127 gtk_widget_destroy (state->dialog);
128 return;
131 static void
132 cb_dialog_so_size_value_changed (G_GNUC_UNUSED GtkSpinButton *spinbutton,
133 SOSizeState *state)
135 int width, height;
136 int new_width, new_height;
137 int dx, dy;
139 width = state->coords[2] - state->coords[0];
140 height = state->coords[3] - state->coords[1];
141 if (width < 0) width = - width;
142 if (height < 0) height = - height;
144 new_width = gtk_spin_button_get_value_as_int (state->wspin);
145 new_height = gtk_spin_button_get_value_as_int (state->hspin);
146 dx = gtk_spin_button_get_value_as_int (state->xspin);
147 dy = gtk_spin_button_get_value_as_int (state->yspin);
149 state->so_size_needs_restore = (new_width != width) || (new_height != height);
150 state->so_pos_needs_restore = (dx != 0) || (dy != 0);
152 *(state->active_anchor) = *(state->old_anchor);
154 if (state->so_size_needs_restore || state->so_pos_needs_restore) {
155 gdouble new_coords[4];
157 new_coords[0] = state->coords[0] + dx;
158 new_coords[1] = state->coords[1] + dy;
159 new_coords[2] = state->coords[2] + dx;
160 new_coords[3] = state->coords[3] + dy;
161 if (new_coords[0] < new_coords[2])
162 new_coords[2] = new_coords[0] + new_width;
163 else
164 new_coords[0] = new_coords[2] + new_width;
165 if (new_coords[1] < new_coords[3])
166 new_coords[3] = new_coords[1] + new_height;
167 else
168 new_coords[1] = new_coords[3] + new_height;
170 scg_object_coords_to_anchor (state->scg, new_coords,
171 state->active_anchor);
174 sheet_object_set_anchor (state->so, state->active_anchor);
176 dialog_so_size_button_sensitivity (state);
179 static void
180 dialog_so_size_load (SOSizeState *state)
182 g_free (state->old_anchor);
183 state->old_anchor = sheet_object_anchor_dup
184 (sheet_object_get_anchor (state->so));
185 scg_object_anchor_to_coords (state->scg,
186 state->old_anchor,
187 state->coords);
188 state->so_size_needs_restore = FALSE;
189 state->so_pos_needs_restore = FALSE;
192 static GOUndo *
193 set_params (SheetObject *so, char *name)
195 return go_undo_binary_new
196 (g_object_ref (so), name,
197 (GOUndoBinaryFunc)sheet_object_set_name,
198 g_object_unref, g_free);
201 static GOUndo *
202 set_print_flag (SheetObject *so, gboolean print)
204 gboolean *p_print = g_new (gboolean, 1);
206 *p_print = print;
207 return go_undo_binary_new
208 (g_object_ref (so), p_print,
209 (GOUndoBinaryFunc)sheet_object_set_print_flag,
210 g_object_unref, g_free);
213 static GOUndo *
214 set_mode (SheetObject *so, GnmSOAnchorMode mode)
216 GnmSOAnchorMode *p_mode = g_new (GnmSOAnchorMode, 1);
218 *p_mode = mode;
219 return go_undo_binary_new
220 (g_object_ref (so), p_mode,
221 (GOUndoBinaryFunc)sheet_object_set_anchor_mode,
222 g_object_unref, g_free);
225 static void
226 cb_dialog_so_size_apply_clicked (G_GNUC_UNUSED GtkWidget *button,
227 SOSizeState *state)
229 char const *name;
230 GOUndo *undo = NULL, *redo = NULL;
231 char const *undo_name = NULL;
232 int cnt = 0;
234 if (state->so_size_needs_restore || state->so_pos_needs_restore) {
235 char const *label = state->so_pos_needs_restore ?
236 _("Move Object") : _("Resize Object");
237 sheet_object_set_anchor (state->so, state->old_anchor);
238 if (!cmd_objects_move (GNM_WBC (state->wbcg),
239 g_slist_prepend (NULL, state->so),
240 g_slist_prepend
241 (NULL, sheet_object_anchor_dup
242 (state->active_anchor)),
243 FALSE, label))
244 dialog_so_size_load (state);
247 name = gtk_entry_get_text (state->nameentry);
248 if (name == NULL)
249 name = "";
250 if (strcmp (name, state->old_name) != 0) {
251 char *old_name, *new_name;
253 g_object_get (G_OBJECT (state->so), "name", &old_name, NULL);
254 undo = go_undo_combine (undo, set_params (state->so, old_name));
256 new_name = (*name == '\0') ? NULL : g_strdup (name);
257 redo = go_undo_combine (redo, set_params (state->so, new_name));
259 undo_name = _("Set Object Name");
260 cnt++;
262 if (state->so_print_check_changed) {
263 gboolean val = ((state->so->flags & SHEET_OBJECT_PRINT) != 0);
264 undo = go_undo_combine (undo, set_print_flag
265 (state->so, val));
266 redo = go_undo_combine (redo, set_print_flag
267 (state->so, !val));
268 undo_name = _("Set Object Print Property");
269 cnt++;
271 if (state->so_mode_changed) {
272 int new_mode = gnm_so_anchor_mode_chooser_get_mode (state->modecombo);
273 int old_mode = state->so->anchor.mode;
274 undo = go_undo_combine (undo, set_mode (state->so, old_mode));
275 redo = go_undo_combine (redo, set_mode (state->so, new_mode));
276 undo_name = _("Set Object Anchor Mode");
277 cnt++;
280 if (cnt > 0) {
281 if (cnt > 1)
282 undo_name = _("Set Object Properties");
283 state->so_name_changed = state->so_print_check_changed = state->so_mode_changed =
284 cmd_generic (GNM_WBC (state->wbcg),
285 undo_name, undo, redo);
287 dialog_so_size_button_sensitivity (state);
289 return;
292 static void
293 cb_dialog_so_size_ok_clicked (GtkWidget *button, SOSizeState *state)
295 cb_dialog_so_size_apply_clicked (button, state);
296 if (!state->so_size_needs_restore && !state->so_pos_needs_restore &&
297 !state->so_name_changed && !state->so_print_check_changed)
298 gtk_widget_destroy (state->dialog);
299 return;
302 static gboolean
303 cb_dialog_so_size_name_changed (GtkEntry *entry,
304 GdkEventFocus *event,
305 SOSizeState *state)
307 char const *name = gtk_entry_get_text (entry);
308 if (name == NULL)
309 name = "";
310 state->so_name_changed
311 = (strcmp (name, state->old_name) != 0);
312 dialog_so_size_button_sensitivity (state);
313 return FALSE;
316 static void
317 cb_dialog_so_size_print_check_toggled (GtkToggleButton *togglebutton,
318 SOSizeState *state)
320 gboolean new_print = !gtk_toggle_button_get_active (togglebutton);
321 gboolean old_print = ((state->so->flags & SHEET_OBJECT_PRINT) != 0);
323 state->so_print_check_changed
324 = (new_print != old_print);
325 dialog_so_size_button_sensitivity (state);
326 return;
329 static void
330 cb_dialog_so_size_mode_changed (GnmSOAnchorModeChooser *chooser, SOSizeState *state)
332 GnmSOAnchorMode new_mode = gnm_so_anchor_mode_chooser_get_mode (chooser);
333 GnmSOAnchorMode old_mode = state->so->anchor.mode;
334 double coords[4];
336 scg_object_anchor_to_coords (state->scg, state->active_anchor, coords);
337 state->active_anchor->mode = new_mode;
338 scg_object_coords_to_anchor (state->scg, coords, state->active_anchor);
339 state->so_mode_changed = new_mode != old_mode;
340 dialog_so_size_button_sensitivity (state);
343 void
344 dialog_so_size (WBCGtk *wbcg, GObject *so)
346 GtkBuilder *gui;
347 SOSizeState *state;
348 GtkGrid *grid;
349 int width, height;
351 g_return_if_fail (wbcg != NULL);
353 if (gnm_dialog_raise_if_exists (wbcg, SO_SIZE_DIALOG_KEY))
354 return;
355 gui = gnm_gtk_builder_load ("sheetobject-size.ui", NULL, GO_CMD_CONTEXT (wbcg));
356 if (gui == NULL)
357 return;
359 state = g_new (SOSizeState, 1);
360 state->wbcg = wbcg;
361 state->sv = wb_control_cur_sheet_view (GNM_WBC (wbcg));
362 state->sheet = sv_sheet (state->sv);
363 state->scg = wbcg_get_nth_scg (wbcg, state->sheet->index_in_wb);
364 state->gui = gui;
365 state->dialog = go_gtk_builder_get_widget (state->gui, "object-size");
367 state->so = GNM_SO (so);
368 g_object_ref (so);
370 state->nameentry = GTK_ENTRY (go_gtk_builder_get_widget (state->gui, "name-entry"));
371 state->old_anchor = NULL;
372 state->old_name = NULL;
373 g_object_get (so, "name", &state->old_name, NULL);
374 if (state->old_name == NULL)
375 state->old_name = g_strdup ("");
376 gtk_entry_set_text (state->nameentry, state->old_name);
377 state->so_name_changed = FALSE;
378 g_signal_connect (G_OBJECT (state->nameentry),
379 "focus-out-event",
380 G_CALLBACK (cb_dialog_so_size_name_changed),
381 state);
382 state->so_print_check_changed = FALSE;
384 state->wpoints = GTK_WIDGET (go_gtk_builder_get_widget (state->gui, "w-pts-label"));
385 state->wspin = GTK_SPIN_BUTTON (go_gtk_builder_get_widget (state->gui, "w-spin"));
386 state->hpoints = GTK_WIDGET (go_gtk_builder_get_widget (state->gui, "h-pts-label"));
387 state->hspin = GTK_SPIN_BUTTON (go_gtk_builder_get_widget (state->gui, "h-spin"));
388 state->xpoints = GTK_WIDGET (go_gtk_builder_get_widget (state->gui, "x-pts-label"));
389 state->xspin = GTK_SPIN_BUTTON (go_gtk_builder_get_widget (state->gui, "x-spin"));
390 state->ypoints = GTK_WIDGET (go_gtk_builder_get_widget (state->gui, "y-pts-label"));
391 state->yspin = GTK_SPIN_BUTTON (go_gtk_builder_get_widget (state->gui, "y-spin"));
392 state->print_check = GTK_WIDGET (go_gtk_builder_get_widget (state->gui,
393 "print-check"));
394 state->modecombo = GNM_SO_ANCHOR_MODE_CHOOSER (gnm_so_anchor_mode_chooser_new (sheet_object_can_resize (state->so)));
395 dialog_so_size_load (state);
396 state->active_anchor = sheet_object_anchor_dup (sheet_object_get_anchor
397 (state->so));
398 width = state->coords[2] - state->coords[0];
399 height = state->coords[3] - state->coords[1];
401 gtk_spin_button_set_value (state->wspin, (width < 0) ? - width : width);
402 gtk_spin_button_set_value (state->hspin, (height < 0) ? - height : height);
403 gtk_spin_button_set_value (state->xspin, 0.);
404 gtk_spin_button_set_value (state->yspin, 0.);
405 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state->print_check),
406 !(state->so->flags & SHEET_OBJECT_PRINT));
407 gnm_so_anchor_mode_chooser_set_mode (state->modecombo,
408 state->so->anchor.mode);
409 grid = GTK_GRID (gtk_builder_get_object (state->gui, "main-grid"));
410 gtk_grid_insert_row (grid, 7);
411 gtk_grid_attach (grid, GTK_WIDGET (state->modecombo), 0, 7, 2, 1);
412 gtk_widget_set_halign (GTK_WIDGET (state->modecombo), GTK_ALIGN_START);
413 gtk_widget_show (GTK_WIDGET (state->modecombo));
414 g_signal_connect (G_OBJECT (state->wspin),
415 "value-changed",
416 G_CALLBACK (cb_dialog_so_size_value_changed_update_points),
417 state->wpoints);
418 g_signal_connect (G_OBJECT (state->hspin),
419 "value-changed",
420 G_CALLBACK (cb_dialog_so_size_value_changed_update_points),
421 state->hpoints);
422 g_signal_connect (G_OBJECT (state->xspin),
423 "value-changed",
424 G_CALLBACK (cb_dialog_so_size_value_changed_update_points),
425 state->xpoints);
426 g_signal_connect (G_OBJECT (state->yspin),
427 "value-changed",
428 G_CALLBACK (cb_dialog_so_size_value_changed_update_points),
429 state->ypoints);
430 g_signal_connect (G_OBJECT (state->print_check),
431 "toggled",
432 G_CALLBACK (cb_dialog_so_size_print_check_toggled),
433 state);
435 cb_dialog_so_size_value_changed_update_points (state->wspin, GTK_LABEL (state->wpoints));
436 cb_dialog_so_size_value_changed_update_points (state->hspin, GTK_LABEL (state->hpoints));
437 cb_dialog_so_size_value_changed_update_points (state->xspin, GTK_LABEL (state->xpoints));
438 cb_dialog_so_size_value_changed_update_points (state->yspin, GTK_LABEL (state->ypoints));
441 g_signal_connect (G_OBJECT (state->wspin),
442 "value-changed",
443 G_CALLBACK (cb_dialog_so_size_value_changed), state);
444 g_signal_connect (G_OBJECT (state->hspin),
445 "value-changed",
446 G_CALLBACK (cb_dialog_so_size_value_changed), state);
447 g_signal_connect (G_OBJECT (state->xspin),
448 "value-changed",
449 G_CALLBACK (cb_dialog_so_size_value_changed), state);
450 g_signal_connect (G_OBJECT (state->yspin),
451 "value-changed",
452 G_CALLBACK (cb_dialog_so_size_value_changed), state);
454 g_signal_connect (G_OBJECT (state->modecombo),
455 "changed",
456 G_CALLBACK (cb_dialog_so_size_mode_changed), state);
458 state->ok_button = go_gtk_builder_get_widget (state->gui, "ok_button");
459 g_signal_connect (G_OBJECT (state->ok_button),
460 "clicked",
461 G_CALLBACK (cb_dialog_so_size_ok_clicked), state);
462 state->apply_button = go_gtk_builder_get_widget (state->gui, "apply_button");
463 g_signal_connect (G_OBJECT (state->apply_button),
464 "clicked",
465 G_CALLBACK (cb_dialog_so_size_apply_clicked), state);
467 state->cancel_button = go_gtk_builder_get_widget (state->gui, "cancel_button");
468 g_signal_connect (G_OBJECT (state->cancel_button),
469 "clicked",
470 G_CALLBACK (cb_dialog_so_size_cancel_clicked), state);
472 gnm_init_help_button (
473 go_gtk_builder_get_widget (state->gui, "help_button"),
474 GNUMERIC_HELP_LINK_SO_SIZE);
476 gnm_dialog_setup_destroy_handlers (GTK_DIALOG (state->dialog),
477 state->wbcg,
478 GNM_DIALOG_DESTROY_CURRENT_SHEET_REMOVED);
480 wbc_gtk_attach_guru (state->wbcg, state->dialog);
481 g_object_set_data_full (G_OBJECT (state->dialog),
482 "state", state, (GDestroyNotify) cb_dialog_so_size_destroy);
484 gnm_keyed_dialog (wbcg, GTK_WINDOW (state->dialog),
485 SO_SIZE_DIALOG_KEY);
486 dialog_so_size_button_sensitivity (state);
487 gtk_widget_show (state->dialog);