1.12.42
[gnumeric.git] / src / dialogs / dialog-sheetobject-size.c
blob7e36a654717f2e79852e265f9d297b5411126c72
1 /*
2 * dialog-sheetobject-size.c:
4 * Author:
5 * Andreas J. Guelzow <aguelzow@pyrshep.ca>
7 * (c) Copyright 2009 Andreas J. Guelzow <aguelzow@pyrshep.ca>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, see <https://www.gnu.org/licenses/>.
22 #include <gnumeric-config.h>
23 #include <glib/gi18n-lib.h>
24 #include <gnumeric.h>
25 #include <string.h>
26 #include <dialogs/dialogs.h>
27 #include <dialogs/help.h>
29 #include <gui-util.h>
30 #include <commands.h>
31 #include <workbook-control.h>
32 #include <workbook.h>
33 #include <wbc-gtk.h>
34 #include <sheet.h>
35 #include <sheet-view.h>
36 #include <application.h>
37 #include <workbook-cmd-format.h>
38 #include <sheet-object-widget.h>
39 #include <sheet-object-impl.h>
40 #include <sheet-control-gui.h>
41 #include <widgets/gnm-so-anchor-mode-chooser.h>
44 #define SO_SIZE_DIALOG_KEY "so-size-dialog"
46 typedef struct {
47 GtkBuilder *gui;
48 WBCGtk *wbcg;
49 Sheet *sheet;
50 SheetView *sv;
51 SheetControlGUI *scg;
52 GtkWidget *dialog;
53 GtkWidget *ok_button;
54 GtkWidget *apply_button;
55 GtkWidget *cancel_button;
56 GtkWidget *wpoints;
57 GtkSpinButton *wspin;
58 GtkWidget *hpoints;
59 GtkSpinButton *hspin;
60 GtkWidget *xpoints;
61 GtkSpinButton *xspin;
62 GtkWidget *ypoints;
63 GtkSpinButton *yspin;
64 GtkEntry *nameentry;
65 GtkWidget *print_check;
66 GnmSOAnchorModeChooser *modecombo;
68 SheetObject *so;
69 SheetObjectAnchor *old_anchor;
70 SheetObjectAnchor *active_anchor;
71 double coords[4];
72 gchar *old_name;
73 gboolean so_size_needs_restore;
74 gboolean so_pos_needs_restore;
75 gboolean so_name_changed;
76 gboolean so_print_check_changed;
77 gboolean so_mode_changed;
78 } SOSizeState;
80 static void
81 cb_dialog_so_size_value_changed_update_points (GtkSpinButton *spinbutton,
82 GtkLabel *points)
84 gint value = gtk_spin_button_get_value_as_int (spinbutton);
85 double size_points = value * 72./gnm_app_display_dpi_get (FALSE);
86 gchar *pts = g_strdup_printf ("%.2f",size_points);
87 gtk_label_set_text (points, pts);
88 g_free (pts);
91 static void
92 dialog_so_size_button_sensitivity (SOSizeState *state)
94 gboolean sensitive = state->so_size_needs_restore ||
95 state->so_pos_needs_restore ||
96 state->so_name_changed ||
97 state->so_print_check_changed ||
98 state->so_mode_changed;
99 gtk_widget_set_sensitive
100 (state->ok_button, sensitive);
101 gtk_widget_set_sensitive
102 (state->apply_button, sensitive);
105 static void
106 cb_dialog_so_size_destroy (SOSizeState *state)
108 if (state->so_size_needs_restore || state->so_pos_needs_restore)
109 sheet_object_set_anchor (state->so, state->old_anchor);
110 g_free (state->old_anchor);
111 g_free (state->active_anchor);
112 g_free (state->old_name);
113 if (state->so!= NULL)
114 g_object_unref (state->so);
115 if (state->gui != NULL)
116 g_object_unref (state->gui);
117 g_free (state);
120 static void
121 cb_dialog_so_size_cancel_clicked (G_GNUC_UNUSED GtkWidget *button,
122 SOSizeState *state)
124 gtk_widget_destroy (state->dialog);
125 return;
128 static void
129 cb_dialog_so_size_value_changed (G_GNUC_UNUSED GtkSpinButton *spinbutton,
130 SOSizeState *state)
132 int width, height;
133 int new_width, new_height;
134 int dx, dy;
136 width = state->coords[2] - state->coords[0];
137 height = state->coords[3] - state->coords[1];
138 if (width < 0) width = - width;
139 if (height < 0) height = - height;
141 new_width = gtk_spin_button_get_value_as_int (state->wspin);
142 new_height = gtk_spin_button_get_value_as_int (state->hspin);
143 dx = gtk_spin_button_get_value_as_int (state->xspin);
144 dy = gtk_spin_button_get_value_as_int (state->yspin);
146 state->so_size_needs_restore = (new_width != width) || (new_height != height);
147 state->so_pos_needs_restore = (dx != 0) || (dy != 0);
149 *(state->active_anchor) = *(state->old_anchor);
151 if (state->so_size_needs_restore || state->so_pos_needs_restore) {
152 gdouble new_coords[4];
154 new_coords[0] = state->coords[0] + dx;
155 new_coords[1] = state->coords[1] + dy;
156 new_coords[2] = state->coords[2] + dx;
157 new_coords[3] = state->coords[3] + dy;
158 if (new_coords[0] < new_coords[2])
159 new_coords[2] = new_coords[0] + new_width;
160 else
161 new_coords[0] = new_coords[2] + new_width;
162 if (new_coords[1] < new_coords[3])
163 new_coords[3] = new_coords[1] + new_height;
164 else
165 new_coords[1] = new_coords[3] + new_height;
167 scg_object_coords_to_anchor (state->scg, new_coords,
168 state->active_anchor);
171 sheet_object_set_anchor (state->so, state->active_anchor);
173 dialog_so_size_button_sensitivity (state);
176 static void
177 dialog_so_size_load (SOSizeState *state)
179 g_free (state->old_anchor);
180 state->old_anchor = sheet_object_anchor_dup
181 (sheet_object_get_anchor (state->so));
182 scg_object_anchor_to_coords (state->scg,
183 state->old_anchor,
184 state->coords);
185 state->so_size_needs_restore = FALSE;
186 state->so_pos_needs_restore = FALSE;
189 static GOUndo *
190 set_params (SheetObject *so, char *name)
192 return go_undo_binary_new
193 (g_object_ref (so), name,
194 (GOUndoBinaryFunc)sheet_object_set_name,
195 g_object_unref, g_free);
198 static GOUndo *
199 set_print_flag (SheetObject *so, gboolean print)
201 gboolean *p_print = g_new (gboolean, 1);
203 *p_print = print;
204 return go_undo_binary_new
205 (g_object_ref (so), p_print,
206 (GOUndoBinaryFunc)sheet_object_set_print_flag,
207 g_object_unref, g_free);
210 static GOUndo *
211 set_mode (SheetObject *so, GnmSOAnchorMode mode)
213 GnmSOAnchorMode *p_mode = g_new (GnmSOAnchorMode, 1);
215 *p_mode = mode;
216 return go_undo_binary_new
217 (g_object_ref (so), p_mode,
218 (GOUndoBinaryFunc)sheet_object_set_anchor_mode,
219 g_object_unref, g_free);
222 static void
223 cb_dialog_so_size_apply_clicked (G_GNUC_UNUSED GtkWidget *button,
224 SOSizeState *state)
226 char const *name;
227 GOUndo *undo = NULL, *redo = NULL;
228 char const *undo_name = NULL;
229 int cnt = 0;
231 if (state->so_size_needs_restore || state->so_pos_needs_restore) {
232 char const *label = state->so_pos_needs_restore ?
233 _("Move Object") : _("Resize Object");
234 sheet_object_set_anchor (state->so, state->old_anchor);
235 if (!cmd_objects_move (GNM_WBC (state->wbcg),
236 g_slist_prepend (NULL, state->so),
237 g_slist_prepend
238 (NULL, sheet_object_anchor_dup
239 (state->active_anchor)),
240 FALSE, label))
241 dialog_so_size_load (state);
244 name = gtk_entry_get_text (state->nameentry);
245 if (name == NULL)
246 name = "";
247 if (strcmp (name, state->old_name) != 0) {
248 char *old_name, *new_name;
250 g_object_get (G_OBJECT (state->so), "name", &old_name, NULL);
251 undo = go_undo_combine (undo, set_params (state->so, old_name));
253 new_name = (*name == '\0') ? NULL : g_strdup (name);
254 redo = go_undo_combine (redo, set_params (state->so, new_name));
256 undo_name = _("Set Object Name");
257 cnt++;
259 if (state->so_print_check_changed) {
260 gboolean val = ((state->so->flags & SHEET_OBJECT_PRINT) != 0);
261 undo = go_undo_combine (undo, set_print_flag
262 (state->so, val));
263 redo = go_undo_combine (redo, set_print_flag
264 (state->so, !val));
265 undo_name = _("Set Object Print Property");
266 cnt++;
268 if (state->so_mode_changed) {
269 int new_mode = gnm_so_anchor_mode_chooser_get_mode (state->modecombo);
270 int old_mode = state->so->anchor.mode;
271 undo = go_undo_combine (undo, set_mode (state->so, old_mode));
272 redo = go_undo_combine (redo, set_mode (state->so, new_mode));
273 undo_name = _("Set Object Anchor Mode");
274 cnt++;
277 if (cnt > 0) {
278 if (cnt > 1)
279 undo_name = _("Set Object Properties");
280 state->so_name_changed = state->so_print_check_changed = state->so_mode_changed =
281 cmd_generic (GNM_WBC (state->wbcg),
282 undo_name, undo, redo);
284 dialog_so_size_button_sensitivity (state);
286 return;
289 static void
290 cb_dialog_so_size_ok_clicked (GtkWidget *button, SOSizeState *state)
292 cb_dialog_so_size_apply_clicked (button, state);
293 if (!state->so_size_needs_restore && !state->so_pos_needs_restore &&
294 !state->so_name_changed && !state->so_print_check_changed)
295 gtk_widget_destroy (state->dialog);
296 return;
299 static gboolean
300 cb_dialog_so_size_name_changed (GtkEntry *entry,
301 GdkEventFocus *event,
302 SOSizeState *state)
304 char const *name = gtk_entry_get_text (entry);
305 if (name == NULL)
306 name = "";
307 state->so_name_changed
308 = (strcmp (name, state->old_name) != 0);
309 dialog_so_size_button_sensitivity (state);
310 return FALSE;
313 static void
314 cb_dialog_so_size_print_check_toggled (GtkToggleButton *togglebutton,
315 SOSizeState *state)
317 gboolean new_print = !gtk_toggle_button_get_active (togglebutton);
318 gboolean old_print = ((state->so->flags & SHEET_OBJECT_PRINT) != 0);
320 state->so_print_check_changed
321 = (new_print != old_print);
322 dialog_so_size_button_sensitivity (state);
323 return;
326 static void
327 cb_dialog_so_size_mode_changed (GnmSOAnchorModeChooser *chooser, SOSizeState *state)
329 GnmSOAnchorMode new_mode = gnm_so_anchor_mode_chooser_get_mode (chooser);
330 GnmSOAnchorMode old_mode = state->so->anchor.mode;
331 double coords[4];
333 scg_object_anchor_to_coords (state->scg, state->active_anchor, coords);
334 state->active_anchor->mode = new_mode;
335 scg_object_coords_to_anchor (state->scg, coords, state->active_anchor);
336 state->so_mode_changed = new_mode != old_mode;
337 dialog_so_size_button_sensitivity (state);
340 void
341 dialog_so_size (WBCGtk *wbcg, GObject *so)
343 GtkBuilder *gui;
344 SOSizeState *state;
345 GtkGrid *grid;
346 int width, height;
348 g_return_if_fail (wbcg != NULL);
350 if (gnm_dialog_raise_if_exists (wbcg, SO_SIZE_DIALOG_KEY))
351 return;
352 gui = gnm_gtk_builder_load ("res:ui/sheetobject-size.ui", NULL, GO_CMD_CONTEXT (wbcg));
353 if (gui == NULL)
354 return;
356 state = g_new (SOSizeState, 1);
357 state->wbcg = wbcg;
358 state->sv = wb_control_cur_sheet_view (GNM_WBC (wbcg));
359 state->sheet = sv_sheet (state->sv);
360 state->scg = wbcg_get_nth_scg (wbcg, state->sheet->index_in_wb);
361 state->gui = gui;
362 state->dialog = go_gtk_builder_get_widget (state->gui, "object-size");
364 state->so = GNM_SO (so);
365 g_object_ref (so);
367 state->nameentry = GTK_ENTRY (go_gtk_builder_get_widget (state->gui, "name-entry"));
368 state->old_anchor = NULL;
369 state->old_name = NULL;
370 g_object_get (so, "name", &state->old_name, NULL);
371 if (state->old_name == NULL)
372 state->old_name = g_strdup ("");
373 gtk_entry_set_text (state->nameentry, state->old_name);
374 state->so_name_changed = FALSE;
375 g_signal_connect (G_OBJECT (state->nameentry),
376 "focus-out-event",
377 G_CALLBACK (cb_dialog_so_size_name_changed),
378 state);
379 state->so_print_check_changed = FALSE;
381 state->wpoints = GTK_WIDGET (go_gtk_builder_get_widget (state->gui, "w-pts-label"));
382 state->wspin = GTK_SPIN_BUTTON (go_gtk_builder_get_widget (state->gui, "w-spin"));
383 state->hpoints = GTK_WIDGET (go_gtk_builder_get_widget (state->gui, "h-pts-label"));
384 state->hspin = GTK_SPIN_BUTTON (go_gtk_builder_get_widget (state->gui, "h-spin"));
385 state->xpoints = GTK_WIDGET (go_gtk_builder_get_widget (state->gui, "x-pts-label"));
386 state->xspin = GTK_SPIN_BUTTON (go_gtk_builder_get_widget (state->gui, "x-spin"));
387 state->ypoints = GTK_WIDGET (go_gtk_builder_get_widget (state->gui, "y-pts-label"));
388 state->yspin = GTK_SPIN_BUTTON (go_gtk_builder_get_widget (state->gui, "y-spin"));
389 state->print_check = GTK_WIDGET (go_gtk_builder_get_widget (state->gui,
390 "print-check"));
391 state->modecombo = GNM_SO_ANCHOR_MODE_CHOOSER (gnm_so_anchor_mode_chooser_new (sheet_object_can_resize (state->so)));
392 dialog_so_size_load (state);
393 state->active_anchor = sheet_object_anchor_dup (sheet_object_get_anchor
394 (state->so));
395 width = state->coords[2] - state->coords[0];
396 height = state->coords[3] - state->coords[1];
398 gtk_spin_button_set_value (state->wspin, (width < 0) ? - width : width);
399 gtk_spin_button_set_value (state->hspin, (height < 0) ? - height : height);
400 gtk_spin_button_set_value (state->xspin, 0.);
401 gtk_spin_button_set_value (state->yspin, 0.);
402 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state->print_check),
403 !(state->so->flags & SHEET_OBJECT_PRINT));
404 gnm_so_anchor_mode_chooser_set_mode (state->modecombo,
405 state->so->anchor.mode);
406 grid = GTK_GRID (gtk_builder_get_object (state->gui, "main-grid"));
407 gtk_grid_insert_row (grid, 7);
408 gtk_grid_attach (grid, GTK_WIDGET (state->modecombo), 0, 7, 2, 1);
409 gtk_widget_set_halign (GTK_WIDGET (state->modecombo), GTK_ALIGN_START);
410 gtk_widget_show (GTK_WIDGET (state->modecombo));
411 g_signal_connect (G_OBJECT (state->wspin),
412 "value-changed",
413 G_CALLBACK (cb_dialog_so_size_value_changed_update_points),
414 state->wpoints);
415 g_signal_connect (G_OBJECT (state->hspin),
416 "value-changed",
417 G_CALLBACK (cb_dialog_so_size_value_changed_update_points),
418 state->hpoints);
419 g_signal_connect (G_OBJECT (state->xspin),
420 "value-changed",
421 G_CALLBACK (cb_dialog_so_size_value_changed_update_points),
422 state->xpoints);
423 g_signal_connect (G_OBJECT (state->yspin),
424 "value-changed",
425 G_CALLBACK (cb_dialog_so_size_value_changed_update_points),
426 state->ypoints);
427 g_signal_connect (G_OBJECT (state->print_check),
428 "toggled",
429 G_CALLBACK (cb_dialog_so_size_print_check_toggled),
430 state);
432 cb_dialog_so_size_value_changed_update_points (state->wspin, GTK_LABEL (state->wpoints));
433 cb_dialog_so_size_value_changed_update_points (state->hspin, GTK_LABEL (state->hpoints));
434 cb_dialog_so_size_value_changed_update_points (state->xspin, GTK_LABEL (state->xpoints));
435 cb_dialog_so_size_value_changed_update_points (state->yspin, GTK_LABEL (state->ypoints));
438 g_signal_connect (G_OBJECT (state->wspin),
439 "value-changed",
440 G_CALLBACK (cb_dialog_so_size_value_changed), state);
441 g_signal_connect (G_OBJECT (state->hspin),
442 "value-changed",
443 G_CALLBACK (cb_dialog_so_size_value_changed), state);
444 g_signal_connect (G_OBJECT (state->xspin),
445 "value-changed",
446 G_CALLBACK (cb_dialog_so_size_value_changed), state);
447 g_signal_connect (G_OBJECT (state->yspin),
448 "value-changed",
449 G_CALLBACK (cb_dialog_so_size_value_changed), state);
451 g_signal_connect (G_OBJECT (state->modecombo),
452 "changed",
453 G_CALLBACK (cb_dialog_so_size_mode_changed), state);
455 state->ok_button = go_gtk_builder_get_widget (state->gui, "ok_button");
456 g_signal_connect (G_OBJECT (state->ok_button),
457 "clicked",
458 G_CALLBACK (cb_dialog_so_size_ok_clicked), state);
459 state->apply_button = go_gtk_builder_get_widget (state->gui, "apply_button");
460 g_signal_connect (G_OBJECT (state->apply_button),
461 "clicked",
462 G_CALLBACK (cb_dialog_so_size_apply_clicked), state);
464 state->cancel_button = go_gtk_builder_get_widget (state->gui, "cancel_button");
465 g_signal_connect (G_OBJECT (state->cancel_button),
466 "clicked",
467 G_CALLBACK (cb_dialog_so_size_cancel_clicked), state);
469 gnm_init_help_button (
470 go_gtk_builder_get_widget (state->gui, "help_button"),
471 GNUMERIC_HELP_LINK_SO_SIZE);
473 gnm_dialog_setup_destroy_handlers (GTK_DIALOG (state->dialog),
474 state->wbcg,
475 GNM_DIALOG_DESTROY_CURRENT_SHEET_REMOVED);
477 wbc_gtk_attach_guru (state->wbcg, state->dialog);
478 g_object_set_data_full (G_OBJECT (state->dialog),
479 "state", state, (GDestroyNotify) cb_dialog_so_size_destroy);
481 gnm_keyed_dialog (wbcg, GTK_WINDOW (state->dialog),
482 SO_SIZE_DIALOG_KEY);
483 dialog_so_size_button_sensitivity (state);
484 gtk_widget_show (state->dialog);