static void view_actions_set_zoom (GimpActionGroup *group, GimpDisplayShell *shell) { const gchar *action = NULL; gchar *str; gchar *label; guint scale; g_object_get (shell->zoom, "percentage", &str, NULL); scale = ROUND (gimp_zoom_model_get_factor (shell->zoom) * 1000); switch (scale) { case 16000: action = "view-zoom-16-1"; break; case 8000: action = "view-zoom-8-1"; break; case 4000: action = "view-zoom-4-1"; break; case 2000: action = "view-zoom-2-1"; break; case 1000: action = "view-zoom-1-1"; break; case 500: action = "view-zoom-1-2"; break; case 250: action = "view-zoom-1-4"; break; case 125: action = "view-zoom-1-8"; break; case 63: case 62: action = "view-zoom-1-16"; break; } if (! action) { action = "view-zoom-other"; label = g_strdup_printf (_("Othe_r (%s)..."), str); gimp_action_group_set_action_label (group, action, label); g_free (label); shell->other_scale = gimp_zoom_model_get_factor (shell->zoom); } gimp_action_group_set_action_active (group, action, TRUE); label = g_strdup_printf (_("_Zoom (%s)"), str); gimp_action_group_set_action_label (group, "view-zoom-menu", label); g_free (label); /* flag as dirty */ shell->other_scale = - fabs (shell->other_scale); g_free (str); }
void gimp_display_shell_scale_drag (GimpDisplayShell *shell, gdouble start_x, gdouble start_y, gdouble delta_x, gdouble delta_y) { gdouble scale; g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); scale = gimp_zoom_model_get_factor (shell->zoom); gimp_display_shell_push_zoom_focus_pointer_pos (shell, start_x, start_y); if (delta_y > 0) { gimp_display_shell_scale (shell, GIMP_ZOOM_TO, scale * 1.1, GIMP_ZOOM_FOCUS_POINTER); } else if (delta_y < 0) { gimp_display_shell_scale (shell, GIMP_ZOOM_TO, scale * 0.9, GIMP_ZOOM_FOCUS_POINTER); } }
/** * gimp_display_shell_scale_by_values: * @shell: the #GimpDisplayShell * @scale: the new scale * @offset_x: the new X offset * @offset_y: the new Y offset * @resize_window: whether the display window should be resized * * Directly sets the image scale and image offsets used by the display. If * @resize_window is %TRUE then the display window is resized to better * accommodate the image, see gimp_display_shell_shrink_wrap(). **/ void gimp_display_shell_scale_by_values (GimpDisplayShell *shell, gdouble scale, gint offset_x, gint offset_y, gboolean resize_window) { g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); /* Abort early if the values are all setup already. We don't * want to inadvertently resize the window (bug #164281). */ if (SCALE_EQUALS (gimp_zoom_model_get_factor (shell->zoom), scale) && shell->offset_x == offset_x && shell->offset_y == offset_y) return; gimp_display_shell_scale_save_revert_values (shell); /* freeze the active tool */ gimp_display_shell_pause (shell); gimp_zoom_model_zoom (shell->zoom, GIMP_ZOOM_TO, scale); shell->offset_x = offset_x; shell->offset_y = offset_y; gimp_display_shell_scale_resize (shell, resize_window, FALSE); /* re-enable the active tool */ gimp_display_shell_resume (shell); }
/** * gimp_display_shell_scale_get_image_size: * @shell: * @w: * @h: * * Gets the size of the rendered image after it has been scaled. * **/ void gimp_display_shell_scale_get_image_size (GimpDisplayShell *shell, gint *w, gint *h) { g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); gimp_display_shell_scale_get_image_size_for_scale (shell, gimp_zoom_model_get_factor (shell->zoom), w, h); }
/** * gimp_zoom_model_zoom: * @model: a #GimpZoomModel * @zoom_type: the #GimpZoomType * @scale: ignored unless @zoom_type == %GIMP_ZOOM_TO * * Since GIMP 2.4 **/ void gimp_zoom_model_zoom (GimpZoomModel *model, GimpZoomType zoom_type, gdouble scale) { g_return_if_fail (GIMP_IS_ZOOM_MODEL (model)); if (zoom_type != GIMP_ZOOM_TO) scale = gimp_zoom_model_get_factor (model); g_object_set (model, "value", gimp_zoom_model_zoom_step (zoom_type, scale), NULL); }
void view_new_cmd_callback (GtkAction *action, gpointer data) { GimpDisplay *display; GimpDisplayShell *shell; return_if_no_display (display, data); shell = gimp_display_get_shell (display); gimp_create_display (display->gimp, gimp_display_get_image (display), shell->unit, gimp_zoom_model_get_factor (shell->zoom)); }
void view_new_cmd_callback (GtkAction *action, gpointer data) { GimpDisplay *display; GimpDisplayShell *shell; return_if_no_display (display, data); shell = gimp_display_get_shell (display); gimp_create_display (display->gimp, gimp_display_get_image (display), shell->unit, gimp_zoom_model_get_factor (shell->zoom), G_OBJECT (gtk_widget_get_screen (GTK_WIDGET (shell))), gimp_widget_get_monitor (GTK_WIDGET (shell))); }
void view_zoom_other_cmd_callback (GtkAction *action, gpointer data) { GimpDisplayShell *shell; return_if_no_shell (shell, data); /* check if we are activated by the user or from * view_actions_set_zoom() */ if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)) && shell->other_scale != gimp_zoom_model_get_factor (shell->zoom)) { gimp_display_shell_scale_dialog (shell); } }
/** * gimp_display_shell_scale_save_revert_values: * @shell: * * Handle the updating of the Revert Zoom variables. **/ void gimp_display_shell_scale_save_revert_values (GimpDisplayShell *shell) { guint now; g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); now = time (NULL); if (now - shell->last_scale_time >= SCALE_TIMEOUT) { shell->last_scale = gimp_zoom_model_get_factor (shell->zoom); shell->last_offset_x = shell->offset_x; shell->last_offset_y = shell->offset_y; } shell->last_scale_time = now; }
/** * gimp_display_shell_scale_fit_or_fill: * @shell: the #GimpDisplayShell * @fill: whether to scale the image to fill the viewport, * or fit inside the viewport * * A common implementation for gimp_display_shell_scale_{fit_in,fill}(). **/ static void gimp_display_shell_scale_fit_or_fill (GimpDisplayShell *shell, gboolean fill) { GimpImage *image; gdouble image_x; gdouble image_y; gdouble image_width; gdouble image_height; gdouble current_scale; gdouble zoom_factor; image = gimp_display_get_image (shell->display); gimp_display_shell_transform_bounds (shell, 0, 0, gimp_image_get_width (image), gimp_image_get_height (image), &image_x, &image_y, &image_width, &image_height); image_width -= image_x; image_height -= image_y; current_scale = gimp_zoom_model_get_factor (shell->zoom); if (fill) { zoom_factor = MAX (shell->disp_width / image_width, shell->disp_height / image_height); } else { zoom_factor = MIN (shell->disp_width / image_width, shell->disp_height / image_height); } gimp_display_shell_scale (shell, GIMP_ZOOM_TO, zoom_factor * current_scale, GIMP_ZOOM_FOCUS_BEST_GUESS); gimp_display_shell_scroll_center_image (shell, TRUE, TRUE); }
void image_duplicate_cmd_callback (GtkAction *action, gpointer data) { GimpDisplay *display; GimpDisplayShell *shell; GimpImage *new_image; return_if_no_display (display, data); shell = GIMP_DISPLAY_SHELL (display->shell); new_image = gimp_image_duplicate (display->image); gimp_create_display (new_image->gimp, new_image, shell->unit, gimp_zoom_model_get_factor (shell->zoom)); g_object_unref (new_image); }
void view_zoom_explicit_cmd_callback (GtkAction *action, GtkAction *current, gpointer data) { GimpDisplayShell *shell; gint value; return_if_no_shell (shell, data); value = gtk_radio_action_get_current_value (GTK_RADIO_ACTION (action)); if (value != 0 /* not Other... */) { if (fabs (value - gimp_zoom_model_get_factor (shell->zoom)) > 0.0001) gimp_display_shell_scale (shell, GIMP_ZOOM_TO, (gdouble) value / 10000, GIMP_ZOOM_FOCUS_RETAIN_CENTERING_ELSE_BEST_GUESS); } }
/* We used to calculate the scale factor in the SCALEFACTOR_X() and * SCALEFACTOR_Y() macros. But since these are rather frequently * called and the values rarely change, we now store them in the * shell and call this function whenever they need to be recalculated. */ void gimp_display_shell_scale_update (GimpDisplayShell *shell) { GimpImage *image; g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); image = gimp_display_get_image (shell->display); if (image) { gimp_display_shell_calculate_scale_x_and_y (shell, gimp_zoom_model_get_factor (shell->zoom), &shell->scale_x, &shell->scale_y); } else { shell->scale_x = 1.0; shell->scale_y = 1.0; } }
static void gimp_navigation_editor_shell_scaled (GimpDisplayShell *shell, GimpNavigationEditor *editor) { if (editor->zoom_label) { gchar *str; g_object_get (shell->zoom, "percentage", &str, NULL); gtk_label_set_text (GTK_LABEL (editor->zoom_label), str); g_free (str); } if (editor->zoom_adjustment) { gdouble val; val = log (gimp_zoom_model_get_factor (shell->zoom)) / G_LN2; g_signal_handlers_block_by_func (editor->zoom_adjustment, gimp_navigation_editor_zoom_adj_changed, editor); gtk_adjustment_set_value (editor->zoom_adjustment, val); g_signal_handlers_unblock_by_func (editor->zoom_adjustment, gimp_navigation_editor_zoom_adj_changed, editor); } gimp_navigation_editor_update_marker (editor); if (gimp_editor_get_ui_manager (GIMP_EDITOR (editor))) gimp_ui_manager_update (gimp_editor_get_ui_manager (GIMP_EDITOR (editor)), gimp_editor_get_popup_data (GIMP_EDITOR (editor))); }
void gimp_display_shell_canvas_size_allocate (GtkWidget *widget, GtkAllocation *allocation, GimpDisplayShell *shell) { /* are we in destruction? */ if (! shell->display || ! gimp_display_get_shell (shell->display)) return; if ((shell->disp_width != allocation->width) || (shell->disp_height != allocation->height)) { if (shell->zoom_on_resize && shell->disp_width > 64 && shell->disp_height > 64 && allocation->width > 64 && allocation->height > 64) { gdouble scale = gimp_zoom_model_get_factor (shell->zoom); gint offset_x; gint offset_y; /* FIXME: The code is a bit of a mess */ /* multiply the zoom_factor with the ratio of the new and * old canvas diagonals */ scale *= (sqrt (SQR (allocation->width) + SQR (allocation->height)) / sqrt (SQR (shell->disp_width) + SQR (shell->disp_height))); offset_x = UNSCALEX (shell, shell->offset_x); offset_y = UNSCALEX (shell, shell->offset_y); gimp_zoom_model_zoom (shell->zoom, GIMP_ZOOM_TO, scale); shell->offset_x = SCALEX (shell, offset_x); shell->offset_y = SCALEY (shell, offset_y); } shell->disp_width = allocation->width; shell->disp_height = allocation->height; /* When we size-allocate due to resize of the top level window, * we want some additional logic. Don't apply it on * zoom_on_resize though. */ if (shell->size_allocate_from_configure_event && ! shell->zoom_on_resize) { gboolean center_horizontally; gboolean center_vertically; gint target_offset_x; gint target_offset_y; gint sw; gint sh; gimp_display_shell_scale_get_image_size (shell, &sw, &sh); center_horizontally = sw <= shell->disp_width; center_vertically = sh <= shell->disp_height; gimp_display_shell_scroll_center_image (shell, center_horizontally, center_vertically); /* This is basically the best we can do before we get an * API for storing the image offset at the start of an * image window resize using the mouse */ target_offset_x = shell->offset_x; target_offset_y = shell->offset_y; if (! center_horizontally) { target_offset_x = MAX (shell->offset_x, 0); } if (! center_vertically) { target_offset_y = MAX (shell->offset_y, 0); } gimp_display_shell_scroll_set_offset (shell, target_offset_x, target_offset_y); } gimp_display_shell_scroll_clamp_and_update (shell); gimp_display_shell_scaled (shell); /* Reset */ shell->size_allocate_from_configure_event = FALSE; } }
static gint gimp_display_shell_format_title (GimpDisplayShell *shell, gchar *title, gint title_len, const gchar *format) { GimpImage *image; gint num, denom; gint i = 0; g_return_val_if_fail (GIMP_IS_DISPLAY_SHELL (shell), 0); image = gimp_display_get_image (shell->display); if (! image) { title[0] = '\n'; return 0; } gimp_zoom_model_get_fraction (shell->zoom, &num, &denom); while (i < title_len && *format) { switch (*format) { case '%': format++; switch (*format) { case 0: /* format string ends within %-sequence, print literal '%' */ case '%': title[i++] = '%'; break; case 'f': /* base filename */ i += print (title, title_len, i, "%s", gimp_image_get_display_name (image)); break; case 'F': /* full filename */ i += print (title, title_len, i, "%s", gimp_image_get_display_path (image)); break; case 'p': /* PDB id */ i += print (title, title_len, i, "%d", gimp_image_get_ID (image)); break; case 'i': /* instance */ i += print (title, title_len, i, "%d", gimp_display_get_instance (shell->display)); break; case 't': /* image type */ i += print (title, title_len, i, "%s %s", gimp_display_shell_title_image_type (image), gimp_display_shell_title_image_precision (image)); break; case 'T': /* drawable type */ { GimpDrawable *drawable = gimp_image_get_active_drawable (image); const Babl *format = gimp_drawable_get_format (drawable); if (drawable) i += print (title, title_len, i, "%s", gimp_babl_get_description (format)); } break; case 's': /* user source zoom factor */ i += print (title, title_len, i, "%d", denom); break; case 'd': /* user destination zoom factor */ i += print (title, title_len, i, "%d", num); break; case 'z': /* user zoom factor (percentage) */ { gdouble scale = gimp_zoom_model_get_factor (shell->zoom); i += print (title, title_len, i, scale >= 0.15 ? "%.0f" : "%.2f", 100.0 * scale); } break; case 'D': /* dirty flag */ if (format[1] == 0) { /* format string ends within %D-sequence, print literal '%D' */ i += print (title, title_len, i, "%%D"); break; } if (gimp_image_is_dirty (image)) title[i++] = format[1]; format++; break; case 'C': /* clean flag */ if (format[1] == 0) { /* format string ends within %C-sequence, print literal '%C' */ i += print (title, title_len, i, "%%C"); break; } if (! gimp_image_is_dirty (image)) title[i++] = format[1]; format++; break; case 'B': /* dirty flag (long) */ if (gimp_image_is_dirty (image)) i += print (title, title_len, i, "%s", _("(modified)")); break; case 'A': /* clean flag (long) */ if (! gimp_image_is_dirty (image)) i += print (title, title_len, i, "%s", _("(clean)")); break; case 'm': /* memory used by image */ { GimpObject *object = GIMP_OBJECT (image); gchar *str; str = g_format_size (gimp_object_get_memsize (object, NULL)); i += print (title, title_len, i, "%s", str); g_free (str); } break; case 'M': /* image size in megapixels */ i += print (title, title_len, i, "%.1f", (gdouble) gimp_image_get_width (image) * (gdouble) gimp_image_get_height (image) / 1000000.0); break; case 'l': /* number of layers */ i += print (title, title_len, i, "%d", gimp_image_get_n_layers (image)); break; case 'L': /* number of layers (long) */ { gint num = gimp_image_get_n_layers (image); i += print (title, title_len, i, ngettext ("%d layer", "%d layers", num), num); } break; case 'n': /* active drawable name */ { GimpDrawable *drawable = gimp_image_get_active_drawable (image); if (drawable) { gchar *desc; desc = gimp_viewable_get_description (GIMP_VIEWABLE (drawable), NULL); i += print (title, title_len, i, "%s", desc); g_free (desc); } else { i += print (title, title_len, i, "%s", _("(none)")); } } break; case 'P': /* active drawable PDB id */ { GimpDrawable *drawable = gimp_image_get_active_drawable (image); if (drawable) i += print (title, title_len, i, "%d", gimp_item_get_ID (GIMP_ITEM (drawable))); else i += print (title, title_len, i, "%s", _("(none)")); } break; case 'W': /* width in real-world units */ if (shell->unit != GIMP_UNIT_PIXEL) { gdouble xres; gdouble yres; gchar unit_format[8]; gimp_image_get_resolution (image, &xres, &yres); g_snprintf (unit_format, sizeof (unit_format), "%%.%df", gimp_unit_get_digits (shell->unit) + 1); i += print (title, title_len, i, unit_format, gimp_pixels_to_units (gimp_image_get_width (image), shell->unit, xres)); break; } /* else fallthru */ case 'w': /* width in pixels */ i += print (title, title_len, i, "%d", gimp_image_get_width (image)); break; case 'H': /* height in real-world units */ if (shell->unit != GIMP_UNIT_PIXEL) { gdouble xres; gdouble yres; gchar unit_format[8]; gimp_image_get_resolution (image, &xres, &yres); g_snprintf (unit_format, sizeof (unit_format), "%%.%df", gimp_unit_get_digits (shell->unit) + 1); i += print (title, title_len, i, unit_format, gimp_pixels_to_units (gimp_image_get_height (image), shell->unit, yres)); break; } /* else fallthru */ case 'h': /* height in pixels */ i += print (title, title_len, i, "%d", gimp_image_get_height (image)); break; case 'u': /* unit symbol */ i += print (title, title_len, i, "%s", gimp_unit_get_symbol (shell->unit)); break; case 'U': /* unit abbreviation */ i += print (title, title_len, i, "%s", gimp_unit_get_abbreviation (shell->unit)); break; /* Other cool things to be added: * %r = xresolution * %R = yresolution * %ø = image's fractal dimension * %þ = the answer to everything */ default: /* format string contains unknown %-sequence, print it literally */ i += print (title, title_len, i, "%%%c", *format); break; } break; default: title[i++] = *format; break; } format++; } title[MIN (i, title_len - 1)] = '\0'; return i; }
/** * gimp_display_shell_scale: * @shell: the #GimpDisplayShell * @zoom_type: whether to zoom in, our or to a specific scale * @scale: ignored unless @zoom_type == %GIMP_ZOOM_TO * * This function figures out the context of the zoom and behaves * appropriatley thereafter. * **/ void gimp_display_shell_scale (GimpDisplayShell *shell, GimpZoomType zoom_type, gdouble new_scale, GimpZoomFocus zoom_focus) { gint x, y; gdouble current_scale; gdouble real_new_scale; g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); g_return_if_fail (shell->canvas != NULL); current_scale = gimp_zoom_model_get_factor (shell->zoom); if (zoom_type != GIMP_ZOOM_TO) { real_new_scale = gimp_zoom_model_zoom_step (zoom_type, current_scale); } else { real_new_scale = new_scale; } if (! SCALE_EQUALS (real_new_scale, current_scale)) { if (shell->display->config->resize_windows_on_zoom) { GimpImageWindow *window = gimp_display_shell_get_window (shell); /* If the window is resized on zoom, simply do the zoom and * get things rolling */ gimp_zoom_model_zoom (shell->zoom, GIMP_ZOOM_TO, real_new_scale); gimp_display_shell_scaled (shell); if (window && gimp_image_window_get_active_shell (window) == shell) { gimp_image_window_shrink_wrap (window, FALSE); } } else { gboolean starts_fitting_horiz; gboolean starts_fitting_vert; gboolean zoom_focus_almost_centered_horiz; gboolean zoom_focus_almost_centered_vert; gboolean image_center_almost_centered_horiz; gboolean image_center_almost_centered_vert; gint image_center_x; gint image_center_y; gimp_display_shell_scale_get_zoom_focus (shell, real_new_scale, current_scale, &x, &y, zoom_focus); gimp_display_shell_scale_get_image_center_viewport (shell, &image_center_x, &image_center_y); gimp_display_shell_scale_to (shell, real_new_scale, x, y); /* If an image axis started to fit due to zooming out or if * the focus point is as good as in the center, center on * that axis */ gimp_display_shell_scale_image_starts_to_fit (shell, real_new_scale, current_scale, &starts_fitting_horiz, &starts_fitting_vert); gimp_display_shell_scale_viewport_coord_almost_centered (shell, x, y, &zoom_focus_almost_centered_horiz, &zoom_focus_almost_centered_vert); gimp_display_shell_scale_viewport_coord_almost_centered (shell, image_center_x, image_center_y, &image_center_almost_centered_horiz, &image_center_almost_centered_vert); gimp_display_shell_scroll_center_image (shell, starts_fitting_horiz || (zoom_focus_almost_centered_horiz && image_center_almost_centered_horiz), starts_fitting_vert || (zoom_focus_almost_centered_vert && image_center_almost_centered_vert)); } } }
void view_zoom_cmd_callback (GtkAction *action, gint value, gpointer data) { GimpDisplayShell *shell; return_if_no_shell (shell, data); switch ((GimpActionSelectType) value) { case GIMP_ACTION_SELECT_FIRST: gimp_display_shell_scale (shell, GIMP_ZOOM_OUT_MAX, 0.0, GIMP_ZOOM_FOCUS_BEST_GUESS); break; case GIMP_ACTION_SELECT_LAST: gimp_display_shell_scale (shell, GIMP_ZOOM_IN_MAX, 0.0, GIMP_ZOOM_FOCUS_BEST_GUESS); break; case GIMP_ACTION_SELECT_PREVIOUS: gimp_display_shell_scale (shell, GIMP_ZOOM_OUT, 0.0, GIMP_ZOOM_FOCUS_BEST_GUESS); break; case GIMP_ACTION_SELECT_NEXT: gimp_display_shell_scale (shell, GIMP_ZOOM_IN, 0.0, GIMP_ZOOM_FOCUS_BEST_GUESS); break; case GIMP_ACTION_SELECT_SKIP_PREVIOUS: gimp_display_shell_scale (shell, GIMP_ZOOM_OUT_MORE, 0.0, GIMP_ZOOM_FOCUS_BEST_GUESS); break; case GIMP_ACTION_SELECT_SKIP_NEXT: gimp_display_shell_scale (shell, GIMP_ZOOM_IN_MORE, 0.0, GIMP_ZOOM_FOCUS_BEST_GUESS); break; default: { gdouble scale = gimp_zoom_model_get_factor (shell->zoom); scale = action_select_value ((GimpActionSelectType) value, scale, 0.0, 512.0, 1.0, 1.0 / 8.0, 1.0, 16.0, 0.0, FALSE); /* min = 1.0 / 256, max = 256.0 */ /* scale = min * (max / min)**(i/n), i = 0..n */ scale = pow (65536.0, scale / 512.0) / 256.0; gimp_display_shell_scale (shell, GIMP_ZOOM_TO, scale, GIMP_ZOOM_FOCUS_BEST_GUESS); break; } } }
/** * gimp_display_shell_scale_dialog: * @shell: the #GimpDisplayShell * * Constructs and displays a dialog allowing the user to enter a * custom display scale. **/ void gimp_display_shell_scale_dialog (GimpDisplayShell *shell) { ScaleDialogData *data; GimpImage *image; GtkWidget *toplevel; GtkWidget *hbox; GtkWidget *grid; GtkWidget *spin; GtkWidget *label; gint num, denom, row; g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); if (shell->scale_dialog) { gtk_window_present (GTK_WINDOW (shell->scale_dialog)); return; } if (SCALE_EQUALS (shell->other_scale, 0.0)) { /* other_scale not yet initialized */ shell->other_scale = gimp_zoom_model_get_factor (shell->zoom); } image = gimp_display_get_image (shell->display); data = g_slice_new (ScaleDialogData); data->shell = shell; data->model = g_object_new (GIMP_TYPE_ZOOM_MODEL, "value", fabs (shell->other_scale), NULL); shell->scale_dialog = gimp_viewable_dialog_new (GIMP_VIEWABLE (image), gimp_get_user_context (shell->display->gimp), _("Zoom Ratio"), "display_scale", "zoom-original", _("Select Zoom Ratio"), GTK_WIDGET (shell), gimp_standard_help_func, GIMP_HELP_VIEW_ZOOM_OTHER, _("_Cancel"), GTK_RESPONSE_CANCEL, _("_OK"), GTK_RESPONSE_OK, NULL); gimp_dialog_set_alternative_button_order (GTK_DIALOG (shell->scale_dialog), GTK_RESPONSE_OK, GTK_RESPONSE_CANCEL, -1); g_object_weak_ref (G_OBJECT (shell->scale_dialog), (GWeakNotify) gimp_display_shell_scale_dialog_free, data); g_object_weak_ref (G_OBJECT (shell->scale_dialog), (GWeakNotify) g_object_unref, data->model); g_object_add_weak_pointer (G_OBJECT (shell->scale_dialog), (gpointer) &shell->scale_dialog); toplevel = gtk_widget_get_toplevel (GTK_WIDGET (shell)); gtk_window_set_transient_for (GTK_WINDOW (shell->scale_dialog), GTK_WINDOW (toplevel)); gtk_window_set_destroy_with_parent (GTK_WINDOW (shell->scale_dialog), TRUE); g_signal_connect (shell->scale_dialog, "response", G_CALLBACK (gimp_display_shell_scale_dialog_response), data); grid = gtk_grid_new (); gtk_container_set_border_width (GTK_CONTAINER (grid), 12); gtk_grid_set_column_spacing (GTK_GRID (grid), 6); gtk_grid_set_row_spacing (GTK_GRID (grid), 6); gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (shell->scale_dialog))), grid, TRUE, TRUE, 0); gtk_widget_show (grid); row = 0; hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); gimp_grid_attach_aligned (GTK_GRID (grid), 0, row++, _("Zoom ratio:"), 0.0, 0.5, hbox, 1); gimp_zoom_model_get_fraction (data->model, &num, &denom); data->num_adj = gtk_adjustment_new (num, 1, 256, 1, 8, 0); spin = gimp_spin_button_new (data->num_adj, 1.0, 0); gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spin), TRUE); gtk_entry_set_activates_default (GTK_ENTRY (spin), TRUE); gtk_box_pack_start (GTK_BOX (hbox), spin, TRUE, TRUE, 0); gtk_widget_show (spin); label = gtk_label_new (":"); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); gtk_widget_show (label); data->denom_adj = gtk_adjustment_new (denom, 1, 256, 1, 8, 0); spin = gimp_spin_button_new (data->denom_adj, 1.0, 0); gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spin), TRUE); gtk_entry_set_activates_default (GTK_ENTRY (spin), TRUE); gtk_box_pack_start (GTK_BOX (hbox), spin, TRUE, TRUE, 0); gtk_widget_show (spin); hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); gimp_grid_attach_aligned (GTK_GRID (grid), 0, row++, _("Zoom:"), 0.0, 0.5, hbox, 1); data->scale_adj = gtk_adjustment_new (fabs (shell->other_scale) * 100, 100.0 / 256.0, 25600.0, 10, 50, 0); spin = gimp_spin_button_new (data->scale_adj, 1.0, 2); gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spin), TRUE); gtk_entry_set_activates_default (GTK_ENTRY (spin), TRUE); gtk_box_pack_start (GTK_BOX (hbox), spin, TRUE, TRUE, 0); gtk_widget_show (spin); label = gtk_label_new ("%"); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); gtk_widget_show (label); g_signal_connect (data->scale_adj, "value-changed", G_CALLBACK (update_zoom_values), data); g_signal_connect (data->num_adj, "value-changed", G_CALLBACK (update_zoom_values), data); g_signal_connect (data->denom_adj, "value-changed", G_CALLBACK (update_zoom_values), data); gtk_widget_show (shell->scale_dialog); }
void gimp_display_shell_set_initial_scale (GimpDisplayShell *shell, gdouble scale, gint *display_width, gint *display_height) { GimpImage *image; GdkScreen *screen; gint image_width; gint image_height; gint shell_width; gint shell_height; gint screen_width; gint screen_height; g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); image = gimp_display_get_image (shell->display); screen = gtk_widget_get_screen (GTK_WIDGET (shell)); image_width = gimp_image_get_width (image); image_height = gimp_image_get_height (image); screen_width = gdk_screen_get_width (screen) * 0.75; screen_height = gdk_screen_get_height (screen) * 0.75; /* We need to zoom before we use SCALE[XY] */ gimp_zoom_model_zoom (shell->zoom, GIMP_ZOOM_TO, scale); shell_width = SCALEX (shell, image_width); shell_height = SCALEY (shell, image_height); if (shell->display->config->initial_zoom_to_fit) { /* Limit to the size of the screen... */ if (shell_width > screen_width || shell_height > screen_height) { gdouble new_scale; gdouble current = gimp_zoom_model_get_factor (shell->zoom); new_scale = current * MIN (((gdouble) screen_height) / shell_height, ((gdouble) screen_width) / shell_width); new_scale = gimp_zoom_model_zoom_step (GIMP_ZOOM_OUT, new_scale); /* Since zooming out might skip a zoom step we zoom in * again and test if we are small enough. */ gimp_zoom_model_zoom (shell->zoom, GIMP_ZOOM_TO, gimp_zoom_model_zoom_step (GIMP_ZOOM_IN, new_scale)); if (SCALEX (shell, image_width) > screen_width || SCALEY (shell, image_height) > screen_height) gimp_zoom_model_zoom (shell->zoom, GIMP_ZOOM_TO, new_scale); shell_width = SCALEX (shell, image_width); shell_height = SCALEY (shell, image_height); } } else { /* Set up size like above, but do not zoom to fit. Useful when * working on large images. */ if (shell_width > screen_width) shell_width = screen_width; if (shell_height > screen_height) shell_height = screen_height; } if (display_width) *display_width = shell_width; if (display_height) *display_height = shell_height; }
/** * gimp_zoom_model_get_fraction * @model: a #GimpZoomModel * @numerator: return location for numerator * @denominator: return location for denominator * * Retrieves the current zoom factor of @model as a fraction. * * Since GIMP 2.4 **/ void gimp_zoom_model_get_fraction (GimpZoomModel *model, gint *numerator, gint *denominator) { gint p0, p1, p2; gint q0, q1, q2; gdouble zoom_factor; gdouble remainder, next_cf; gboolean swapped = FALSE; g_return_if_fail (GIMP_IS_ZOOM_MODEL (model)); g_return_if_fail (numerator != NULL && denominator != NULL); zoom_factor = gimp_zoom_model_get_factor (model); /* make sure that zooming behaves symmetrically */ if (zoom_factor < 1.0) { zoom_factor = 1.0 / zoom_factor; swapped = TRUE; } /* calculate the continued fraction for the desired zoom factor */ p0 = 1; q0 = 0; p1 = floor (zoom_factor); q1 = 1; remainder = zoom_factor - p1; while (fabs (remainder) >= 0.0001 && fabs (((gdouble) p1 / q1) - zoom_factor) > 0.0001) { remainder = 1.0 / remainder; next_cf = floor (remainder); p2 = next_cf * p1 + p0; q2 = next_cf * q1 + q0; /* Numerator and Denominator are limited by 256 */ /* also absurd ratios like 170:171 are excluded */ if (p2 > 256 || q2 > 256 || (p2 > 1 && q2 > 1 && p2 * q2 > 200)) break; /* remember the last two fractions */ p0 = p1; p1 = p2; q0 = q1; q1 = q2; remainder = remainder - next_cf; } zoom_factor = (gdouble) p1 / q1; /* hard upper and lower bounds for zoom ratio */ if (zoom_factor > 256.0) { p1 = 256; q1 = 1; } else if (zoom_factor < 1.0 / 256.0) { p1 = 1; q1 = 256; } if (swapped) { *numerator = q1; *denominator = p1; } else { *numerator = p1; *denominator = q1; } }
/** * gimp_display_shell_scale_to_rectangle: * @shell: the #GimpDisplayShell * @zoom_type: whether to zoom in or out * @x: retangle's x in image coordinates * @y: retangle's y in image coordinates * @width: retangle's width in image coordinates * @height: retangle's height in image coordinates * @resize_window: whether the display window should be resized * * Scales and scrolls to a specific image rectangle **/ void gimp_display_shell_scale_to_rectangle (GimpDisplayShell *shell, GimpZoomType zoom_type, gdouble x, gdouble y, gdouble width, gdouble height, gboolean resize_window) { GimpImage *image; gdouble current_scale; gdouble new_scale; gdouble display_width; gdouble display_height; gdouble factor = 1.0; gint offset_x = 0; gint offset_y = 0; gdouble xres; gdouble yres; gdouble screen_xres; gdouble screen_yres; g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); image = gimp_display_get_image (shell->display); width = MAX (1.0, width); height = MAX (1.0, height); current_scale = gimp_zoom_model_get_factor (shell->zoom); display_width = FUNSCALEX (shell, shell->disp_width); display_height = FUNSCALEY (shell, shell->disp_height); switch (zoom_type) { case GIMP_ZOOM_IN: factor = MIN ((display_width / width), (display_height / height)); break; case GIMP_ZOOM_OUT: factor = MAX ((width / display_width), (height / display_height)); break; default: g_return_if_reached (); break; } new_scale = current_scale * factor; gimp_image_get_resolution (image, &xres, &yres); gimp_display_shell_scale_get_screen_resolution (shell, &screen_xres, &screen_yres); switch (zoom_type) { case GIMP_ZOOM_IN: /* move the center of the rectangle to the center of the * viewport: * * new_offset = center of rectangle in new scale screen coords * including offset * - * center of viewport in screen coords without * offset */ offset_x = RINT (new_scale * (x + width / 2.0) * screen_xres / xres - (shell->disp_width / 2.0)); offset_y = RINT (new_scale * (y + height / 2.0) * screen_yres / yres - (shell->disp_height / 2.0)); break; case GIMP_ZOOM_OUT: /* move the center of the viewport to the center of the * rectangle: * * new_offset = center of viewport in new scale screen coords * including offset * - * center of rectangle in screen coords without * offset */ offset_x = RINT (new_scale * UNSCALEX (shell, shell->offset_x + shell->disp_width / 2.0) * screen_xres / xres - (SCALEX (shell, x + width / 2.0) - shell->offset_x)); offset_y = RINT (new_scale * UNSCALEY (shell, shell->offset_y + shell->disp_height / 2.0) * screen_yres / yres - (SCALEY (shell, y + height / 2.0) - shell->offset_y)); break; default: break; } if (new_scale != current_scale || offset_x != shell->offset_x || offset_y != shell->offset_y) { gimp_display_shell_scale_by_values (shell, new_scale, offset_x, offset_y, resize_window); } }
/** * gimp_display_shell_scale: * @shell: the #GimpDisplayShell * @zoom_type: whether to zoom in, our or to a specific scale * @scale: ignored unless @zoom_type == %GIMP_ZOOM_TO * * This function figures out the context of the zoom and behaves * appropriatley thereafter. * **/ void gimp_display_shell_scale (GimpDisplayShell *shell, GimpZoomType zoom_type, gdouble new_scale, GimpZoomFocus zoom_focus) { gdouble current_scale; g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); g_return_if_fail (shell->canvas != NULL); current_scale = gimp_zoom_model_get_factor (shell->zoom); if (zoom_type != GIMP_ZOOM_TO) new_scale = gimp_zoom_model_zoom_step (zoom_type, current_scale); if (! SCALE_EQUALS (new_scale, current_scale)) { GimpDisplayConfig *config = shell->display->config; gboolean resize_window; /* Resize windows only in multi-window mode */ resize_window = (config->resize_windows_on_zoom && ! GIMP_GUI_CONFIG (config)->single_window_mode); if (resize_window) { /* If the window is resized on zoom, simply do the zoom and * get things rolling */ gimp_zoom_model_zoom (shell->zoom, GIMP_ZOOM_TO, new_scale); gimp_display_shell_scale_resize (shell, TRUE, FALSE); } else { gboolean starts_fitting_horiz; gboolean starts_fitting_vert; gboolean zoom_focus_almost_centered_horiz; gboolean zoom_focus_almost_centered_vert; gboolean image_center_almost_centered_horiz; gboolean image_center_almost_centered_vert; gdouble x, y; gint image_center_x; gint image_center_y; gimp_display_shell_scale_get_zoom_focus (shell, new_scale, current_scale, &x, &y, zoom_focus); gimp_display_shell_scale_get_image_center_viewport (shell, &image_center_x, &image_center_y); gimp_display_shell_scale_to (shell, new_scale, x, y); /* If an image axis started to fit due to zooming out or if * the focus point is as good as in the center, center on * that axis */ gimp_display_shell_scale_image_starts_to_fit (shell, new_scale, current_scale, &starts_fitting_horiz, &starts_fitting_vert); gimp_display_shell_scale_viewport_coord_almost_centered (shell, x, y, &zoom_focus_almost_centered_horiz, &zoom_focus_almost_centered_vert); gimp_display_shell_scale_viewport_coord_almost_centered (shell, image_center_x, image_center_y, &image_center_almost_centered_horiz, &image_center_almost_centered_vert); gimp_display_shell_scroll_center_image (shell, starts_fitting_horiz || (zoom_focus_almost_centered_horiz && image_center_almost_centered_horiz), starts_fitting_vert || (zoom_focus_almost_centered_vert && image_center_almost_centered_vert)); } } }
static void gimp_display_shell_format_title (GimpDisplayShell *shell, gchar *title, gint title_len, const gchar *format) { Gimp *gimp; GimpImage *image; gint num, denom; gint i = 0; g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); image = shell->display->image; gimp = image->gimp; gimp_zoom_model_get_fraction (shell->zoom, &num, &denom); while (i < title_len && *format) { switch (*format) { case '%': format++; switch (*format) { case 0: /* format string ends within %-sequence, print literal '%' */ case '%': title[i++] = '%'; break; case 'f': /* pruned filename */ { const gchar *uri = gimp_image_get_uri (image); gchar *basename; basename = file_utils_uri_display_basename (uri); i += print (title, title_len, i, "%s", basename); g_free (basename); } break; case 'F': /* full filename */ { gchar *filename; const gchar *uri = gimp_image_get_uri (image); filename = file_utils_uri_display_name (uri); i += print (title, title_len, i, "%s", filename); g_free (filename); } break; case 'p': /* PDB id */ i += print (title, title_len, i, "%d", gimp_image_get_ID (image)); break; case 'i': /* instance */ i += print (title, title_len, i, "%d", shell->display->instance); break; case 't': /* type */ { const gchar *image_type_str = NULL; gboolean empty = gimp_image_is_empty (image); switch (gimp_image_base_type (image)) { case GIMP_RGB: image_type_str = empty ? _("RGB-empty") : _("RGB"); break; case GIMP_GRAY: image_type_str = empty ? _("grayscale-empty") : _("grayscale"); break; case GIMP_INDEXED: image_type_str = empty ? _("indexed-empty") : _("indexed"); break; default: g_assert_not_reached (); break; } i += print (title, title_len, i, "%s", image_type_str); } break; case 's': /* user source zoom factor */ i += print (title, title_len, i, "%d", denom); break; case 'd': /* user destination zoom factor */ i += print (title, title_len, i, "%d", num); break; case 'z': /* user zoom factor (percentage) */ { gdouble scale = gimp_zoom_model_get_factor (shell->zoom); i += print (title, title_len, i, scale >= 0.15 ? "%.0f" : "%.2f", 100.0 * scale); } break; case 'D': /* dirty flag */ if (format[1] == 0) { /* format string ends within %D-sequence, print literal '%D' */ i += print (title, title_len, i, "%%D"); break; } if (image->dirty) title[i++] = format[1]; format++; break; case 'C': /* clean flag */ if (format[1] == 0) { /* format string ends within %C-sequence, print literal '%C' */ i += print (title, title_len, i, "%%C"); break; } if (! image->dirty) title[i++] = format[1]; format++; break; case 'B': /* dirty flag (long) */ if (image->dirty) i += print (title, title_len, i, "%s", _("(modified)")); break; case 'A': /* clean flag (long) */ if (! image->dirty) i += print (title, title_len, i, "%s", _("(clean)")); break; case 'm': /* memory used by image */ { GimpObject *object = GIMP_OBJECT (image); gchar *str; str = gimp_memsize_to_string (gimp_object_get_memsize (object, NULL)); i += print (title, title_len, i, "%s", str); g_free (str); } break; case 'l': /* number of layers */ i += print (title, title_len, i, "%d", gimp_container_num_children (image->layers)); break; case 'L': /* number of layers (long) */ { gint num = gimp_container_num_children (image->layers); i += print (title, title_len, i, ngettext ("%d layer", "%d layers", num), num); } break; case 'n': /* active drawable name */ { GimpDrawable *drawable = gimp_image_get_active_drawable (image); if (drawable) i += print (title, title_len, i, "%s", gimp_object_get_name (GIMP_OBJECT (drawable))); else i += print (title, title_len, i, "%s", _("(none)")); } break; case 'P': /* active drawable PDB id */ { GimpDrawable *drawable = gimp_image_get_active_drawable (image); if (drawable) i += print (title, title_len, i, "%d", gimp_item_get_ID (GIMP_ITEM (drawable))); else i += print (title, title_len, i, "%s", _("(none)")); } break; case 'W': /* width in real-world units */ if (shell->unit != GIMP_UNIT_PIXEL) { gchar unit_format[8]; g_snprintf (unit_format, sizeof (unit_format), "%%.%df", _gimp_unit_get_digits (gimp, shell->unit) + 1); i += print (title, title_len, i, unit_format, (image->width * _gimp_unit_get_factor (gimp, shell->unit) / image->xresolution)); break; } /* else fallthru */ case 'w': /* width in pixels */ i += print (title, title_len, i, "%d", image->width); break; case 'H': /* height in real-world units */ if (shell->unit != GIMP_UNIT_PIXEL) { gchar unit_format[8]; g_snprintf (unit_format, sizeof (unit_format), "%%.%df", _gimp_unit_get_digits (gimp, shell->unit) + 1); i += print (title, title_len, i, unit_format, (image->height * _gimp_unit_get_factor (gimp, shell->unit) / image->yresolution)); break; } /* else fallthru */ case 'h': /* height in pixels */ i += print (title, title_len, i, "%d", image->height); break; case 'u': /* unit symbol */ i += print (title, title_len, i, "%s", _gimp_unit_get_symbol (gimp, shell->unit)); break; case 'U': /* unit abbreviation */ i += print (title, title_len, i, "%s", _gimp_unit_get_abbreviation (gimp, shell->unit)); break; /* Other cool things to be added: * %r = xresolution * %R = yresolution * %ø = image's fractal dimension * %þ = the answer to everything */ default: /* format string contains unknown %-sequence, print it literally */ i += print (title, title_len, i, "%%%c", *format); break; } break; default: title[i++] = *format; break; } format++; } title[MIN (i, title_len - 1)] = '\0'; }
/** * gimp_display_shell_scale_to_rectangle: * @shell: the #GimpDisplayShell * @zoom_type: whether to zoom in or out * @x: retangle's x in image coordinates * @y: retangle's y in image coordinates * @width: retangle's width in image coordinates * @height: retangle's height in image coordinates * @resize_window: whether the display window should be resized * * Scales and scrolls to a specific image rectangle **/ void gimp_display_shell_scale_to_rectangle (GimpDisplayShell *shell, GimpZoomType zoom_type, gdouble x, gdouble y, gdouble width, gdouble height, gboolean resize_window) { gdouble current_scale; gdouble new_scale; gdouble factor = 1.0; gint offset_x = 0; gint offset_y = 0; g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); gimp_display_shell_transform_bounds (shell, x, y, x + width, y + height, &x, &y, &width, &height); /* Convert scrolled (x1, y1, x2, y2) to unscrolled (x, y, width, height). */ width -= x; height -= y; x += shell->offset_x; y += shell->offset_y; width = MAX (1.0, width); height = MAX (1.0, height); current_scale = gimp_zoom_model_get_factor (shell->zoom); switch (zoom_type) { case GIMP_ZOOM_IN: factor = MIN ((shell->disp_width / width), (shell->disp_height / height)); break; case GIMP_ZOOM_OUT: factor = MAX ((width / shell->disp_width), (height / shell->disp_height)); break; default: g_return_if_reached (); break; } new_scale = current_scale * factor; switch (zoom_type) { case GIMP_ZOOM_IN: /* move the center of the rectangle to the center of the * viewport: * * new_offset = center of rectangle in new scale screen coords * including offset * - * center of viewport in screen coords without * offset */ offset_x = RINT (factor * (x + width / 2.0) - (shell->disp_width / 2)); offset_y = RINT (factor * (y + height / 2.0) - (shell->disp_height / 2)); break; case GIMP_ZOOM_OUT: /* move the center of the viewport to the center of the * rectangle: * * new_offset = center of viewport in new scale screen coords * including offset * - * center of rectangle in screen coords without * offset */ offset_x = RINT (factor * (shell->offset_x + shell->disp_width / 2) - ((x + width / 2.0) - shell->offset_x)); offset_y = RINT (factor * (shell->offset_y + shell->disp_height / 2) - ((y + height / 2.0) - shell->offset_y)); break; default: break; } if (new_scale != current_scale || offset_x != shell->offset_x || offset_y != shell->offset_y) { gimp_display_shell_scale_by_values (shell, new_scale, offset_x, offset_y, resize_window); } }
void gimp_display_shell_set_initial_scale (GimpDisplayShell *shell, gdouble scale, gint *display_width, gint *display_height) { GimpImage *image; GdkRectangle workarea; gint image_width; gint image_height; gint monitor_width; gint monitor_height; gint shell_width; gint shell_height; g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); image = gimp_display_get_image (shell->display); gdk_monitor_get_workarea (shell->initial_monitor, &workarea); image_width = gimp_image_get_width (image); image_height = gimp_image_get_height (image); monitor_width = workarea.width * 0.75; monitor_height = workarea.height * 0.75; /* We need to zoom before we use SCALE[XY] */ gimp_zoom_model_zoom (shell->zoom, GIMP_ZOOM_TO, scale); shell_width = SCALEX (shell, image_width); shell_height = SCALEY (shell, image_height); if (shell->display->config->initial_zoom_to_fit) { /* Limit to the size of the monitor... */ if (shell_width > monitor_width || shell_height > monitor_height) { gdouble new_scale; gdouble current = gimp_zoom_model_get_factor (shell->zoom); new_scale = current * MIN (((gdouble) monitor_height) / shell_height, ((gdouble) monitor_width) / shell_width); new_scale = gimp_zoom_model_zoom_step (GIMP_ZOOM_OUT, new_scale, 0.0); /* Since zooming out might skip a zoom step we zoom in * again and test if we are small enough. */ gimp_zoom_model_zoom (shell->zoom, GIMP_ZOOM_TO, gimp_zoom_model_zoom_step (GIMP_ZOOM_IN, new_scale, 0.0)); if (SCALEX (shell, image_width) > monitor_width || SCALEY (shell, image_height) > monitor_height) gimp_zoom_model_zoom (shell->zoom, GIMP_ZOOM_TO, new_scale); shell_width = SCALEX (shell, image_width); shell_height = SCALEY (shell, image_height); } } else { /* Set up size like above, but do not zoom to fit. Useful when * working on large images. */ shell_width = MIN (shell_width, monitor_width); shell_height = MIN (shell_height, monitor_height); } if (display_width) *display_width = shell_width; if (display_height) *display_height = shell_height; }