Files
gimp/app/display/gimpdisplayshell-scale.c
Michael Natterer cee3baea0f First draft of the "no image open" window, which is implemented as a
2008-03-18  Michael Natterer  <mitch@gimp.org>

	First draft of the "no image open" window, which is implemented as
	a display without image (a view with NULL model). Didn't change
	the display's appearance yet so I can first make sure the display
	without image works properly in all details before hiding these
	details.

	* app/core/gimp-gui.[ch]: add "gimp" parameter to display_create()
	and allow "image" to be NULL.

	* app/core/gimpcontext.c (gimp_context_real_set_display): a
	display's image can be NULL now.

	* app/display/gimpdisplay.[ch]: add Gimp and GimpDisplayConfig
	members.  Add Gimp parameter to gimp_display_shell_new(). Changed
	gimp_display_reconnect() to gimp_display_set_image() and allow to
	set a NULL image.

	* app/gui/gui-vtable.c (gui_display_create): if there is a single
	display without an image, call gimp_display_set_image() on that
	display instead of creating a new one.

	* app/display/gimpdisplayshell-close.c: if the last display is
	closed, don't close it but make it empty. Factored out that code
	to gimp_display_shell_really_close().

	* app/display/gimpdisplayshell-dnd.c: when dropping uris on an
	empty display, open the first one into that display and the other
	ones as layers of the newly opened image. This is consistent with
	dropping on an existing image but maybe needs some discussion.

	* app/display/gimpdisplayshell-callbacks.c: bail out early in the
	tool event callback so tools never have to deal with empty
	displays. In expose(), draw the drop zone on the empty display.

	* app/display/gimpdisplayshell-title.c: set the empty display's
	title to "Gimp - Drop Files".

	* app/display/gimpdisplay-foreach.c
	* app/display/gimpdisplay-handlers.c
	* app/display/gimpdisplayshell-appearance.c
	* app/display/gimpdisplayshell-autoscroll.c
	* app/display/gimpdisplayshell-callbacks.c
	* app/display/gimpdisplayshell-cursor.c
	* app/display/gimpdisplayshell-dnd.c
	* app/display/gimpdisplayshell-draw.c
	* app/display/gimpdisplayshell-filter-dialog.c
	* app/display/gimpdisplayshell-handlers.c
	* app/display/gimpdisplayshell-layer-select.c
	* app/display/gimpdisplayshell-preview.c
	* app/display/gimpdisplayshell-render.c
	* app/display/gimpdisplayshell-scale.c
	* app/display/gimpdisplayshell-scroll.c
	* app/display/gimpdisplayshell-selection.c
	* app/display/gimpdisplayshell-title.c
	* app/display/gimpdisplayshell.c
	* app/display/gimpnavigationeditor.c
	* app/display/gimpstatusbar.c: use display->gimp and
	display->config instead of going via the image. Guard against
	empty displays in some few places (most places can't be
	called). Where needed, use the canvas' dimensions instead of the
	image's dimensions so scroll offsets and scrollbars still have
	sane values instead of the last image's ones.

	* app/actions/actions.c (action_data_get_gimp)
	(action_data_get_context): use display->gimp instead of
	display->image->gimp.

	* app/actions/edit-commands.c (edit_paste_cmd_callback): redirect
	to "paste as new" if there is an empty display.

	* app/actions/tools-commands.c (tools_select_cmd_callback): don't
	initialize the new tool on an empty display.

	* app/actions/view-actions.c (view_actions_update): changed lots
	of sensitivity settings to be insensitive when there is no image
	(instead of no display).

	* app/actions/view-commands.c: use the display's config object
	instead of gimp's.


svn path=/trunk/; revision=25113
2008-03-18 21:22:21 +00:00

851 lines
26 KiB
C

/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include <stdlib.h>
#include <gtk/gtk.h>
#include "libgimpmath/gimpmath.h"
#include "libgimpwidgets/gimpwidgets.h"
#include "display-types.h"
#include "config/gimpdisplayconfig.h"
#include "core/gimp.h"
#include "core/gimpimage.h"
#include "core/gimpunit.h"
#include "widgets/gimphelp-ids.h"
#include "widgets/gimpviewabledialog.h"
#include "gimpdisplay.h"
#include "gimpdisplayshell.h"
#include "gimpdisplayshell-scale.h"
#include "gimpdisplayshell-scroll.h"
#include "gimpdisplayshell-title.h"
#include "gimp-intl.h"
#define SCALE_TIMEOUT 1
#define SCALE_EPSILON 0.0001
#define SCALE_EQUALS(a,b) (fabs ((a) - (b)) < SCALE_EPSILON)
typedef struct
{
GimpDisplayShell *shell;
GimpZoomModel *model;
GtkObject *scale_adj;
GtkObject *num_adj;
GtkObject *denom_adj;
} ScaleDialogData;
/* local function prototypes */
static void gimp_display_shell_scale_dialog_response (GtkWidget *widget,
gint response_id,
ScaleDialogData *dialog);
static void gimp_display_shell_scale_dialog_free (ScaleDialogData *dialog);
static void update_zoom_values (GtkAdjustment *adj,
ScaleDialogData *dialog);
static gdouble img2real (GimpDisplayShell *shell,
gboolean xdir,
gdouble a);
/* public functions */
/**
* gimp_display_shell_scale_setup:
* @shell: the #GimpDisplayShell
*
* Prepares the display for drawing the image at current scale and offset.
* This preparation involves, for example, setting up scrollbars and rulers.
**/
void
gimp_display_shell_scale_setup (GimpDisplayShell *shell)
{
GimpImage *image;
GtkRuler *hruler;
GtkRuler *vruler;
gfloat sx, sy;
gint image_width, image_height;
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
if (! shell->display)
return;
image = shell->display->image;
if (image)
{
image_width = gimp_image_get_width (image);
image_height = gimp_image_get_height (image);
sx = SCALEX (shell, image_width);
sy = SCALEY (shell, image_height);
}
else
{
image_width = shell->disp_width;
image_height = shell->disp_height;
sx = image_width;
sy = image_height;
}
shell->hsbdata->value = shell->offset_x;
shell->hsbdata->upper = sx;
shell->hsbdata->page_size = MIN (sx, shell->disp_width);
shell->hsbdata->page_increment = shell->disp_width / 2;
shell->hsbdata->step_increment = shell->scale_x;
shell->vsbdata->value = shell->offset_y;
shell->vsbdata->upper = sy;
shell->vsbdata->page_size = MIN (sy, shell->disp_height);
shell->vsbdata->page_increment = shell->disp_height / 2;
shell->vsbdata->step_increment = shell->scale_y;
gtk_adjustment_changed (shell->hsbdata);
gtk_adjustment_changed (shell->vsbdata);
hruler = GTK_RULER (shell->hrule);
vruler = GTK_RULER (shell->vrule);
hruler->lower = 0;
if (image)
{
hruler->upper = img2real (shell, TRUE,
FUNSCALEX (shell, shell->disp_width));
hruler->max_size = img2real (shell, TRUE,
MAX (image_width, image_height));
}
else
{
hruler->upper = image_width;
hruler->max_size = MAX (image_width, image_height);
}
vruler->lower = 0;
if (image)
{
vruler->upper = img2real (shell, FALSE,
FUNSCALEY (shell, shell->disp_height));
vruler->max_size = img2real (shell, FALSE,
MAX (image_width, image_height));
}
else
{
vruler->upper = image_height;
vruler->max_size = MAX (image_width, image_height);
}
if (image && sx < shell->disp_width)
{
shell->disp_xoffset = (shell->disp_width - sx) / 2;
hruler->lower -= img2real (shell, TRUE,
FUNSCALEX (shell,
(gdouble) shell->disp_xoffset));
hruler->upper -= img2real (shell, TRUE,
FUNSCALEX (shell,
(gdouble) shell->disp_xoffset));
}
else if (image)
{
shell->disp_xoffset = 0;
hruler->lower += img2real (shell, TRUE,
FUNSCALEX (shell,
(gdouble) shell->offset_x));
hruler->upper += img2real (shell, TRUE,
FUNSCALEX (shell,
(gdouble) shell->offset_x));
}
else
{
shell->disp_xoffset = 0;
}
if (image && sy < shell->disp_height)
{
shell->disp_yoffset = (shell->disp_height - sy) / 2;
vruler->lower -= img2real (shell, FALSE,
FUNSCALEY (shell,
(gdouble) shell->disp_yoffset));
vruler->upper -= img2real (shell, FALSE,
FUNSCALEY (shell,
(gdouble) shell->disp_yoffset));
}
else if (image)
{
shell->disp_yoffset = 0;
vruler->lower += img2real (shell, FALSE,
FUNSCALEY (shell,
(gdouble) shell->offset_y));
vruler->upper += img2real (shell, FALSE,
FUNSCALEY (shell,
(gdouble) shell->offset_y));
}
else
{
shell->disp_yoffset = 0;
}
gtk_widget_queue_draw (GTK_WIDGET (hruler));
gtk_widget_queue_draw (GTK_WIDGET (vruler));
#if 0
g_printerr ("offset_x: %d\n"
"offset_y: %d\n"
"disp_width: %d\n"
"disp_height: %d\n"
"disp_xoffset: %d\n"
"disp_yoffset: %d\n\n",
shell->offset_x, shell->offset_y,
shell->disp_width, shell->disp_height,
shell->disp_xoffset, shell->disp_yoffset);
#endif
}
/**
* gimp_display_shell_scale_revert:
* @shell: the #GimpDisplayShell
*
* Reverts the display to the previously used scale. If no previous scale exist
* then the call does nothing.
*
* Return value: %TRUE if the scale was reverted, otherwise %FALSE.
**/
gboolean
gimp_display_shell_scale_revert (GimpDisplayShell *shell)
{
g_return_val_if_fail (GIMP_IS_DISPLAY_SHELL (shell), FALSE);
/* don't bother if no scale has been set */
if (shell->last_scale < SCALE_EPSILON)
return FALSE;
shell->last_scale_time = 0;
gimp_display_shell_scale_by_values (shell,
shell->last_scale,
shell->last_offset_x,
shell->last_offset_y,
FALSE); /* don't resize the window */
return TRUE;
}
/**
* gimp_display_shell_scale_can_revert:
* @shell: the #GimpDisplayShell
*
* Return value: %TRUE if a previous display scale exists, otherwise %FALSE.
**/
gboolean
gimp_display_shell_scale_can_revert (GimpDisplayShell *shell)
{
g_return_val_if_fail (GIMP_IS_DISPLAY_SHELL (shell), FALSE);
return (shell->last_scale > SCALE_EPSILON);
}
/**
* gimp_display_shell_scale_set_dot_for_dot:
* @shell: the #GimpDisplayShell
* @dot_for_dot: whether "Dot for Dot" should be enabled
*
* If @dot_for_dot is set to %TRUE then the "Dot for Dot" mode (where image and
* screen pixels are of the same size) is activated. Dually, the mode is
* disabled if @dot_for_dot is %FALSE.
**/
void
gimp_display_shell_scale_set_dot_for_dot (GimpDisplayShell *shell,
gboolean dot_for_dot)
{
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
if (dot_for_dot != shell->dot_for_dot)
{
/* freeze the active tool */
gimp_display_shell_pause (shell);
shell->dot_for_dot = dot_for_dot;
gimp_display_shell_scale_changed (shell);
gimp_display_shell_scale_resize (shell,
shell->display->config->resize_windows_on_zoom,
TRUE);
/* re-enable the active tool */
gimp_display_shell_resume (shell);
}
}
/**
* 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 calls gimp_display_shell_scale_to(). It tries to be
* smart whether to use the position of the mouse pointer or the
* center of the display as coordinates.
**/
void
gimp_display_shell_scale (GimpDisplayShell *shell,
GimpZoomType zoom_type,
gdouble new_scale)
{
GdkEvent *event;
gint x, y;
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
g_return_if_fail (shell->canvas != NULL);
if (zoom_type == GIMP_ZOOM_TO &&
SCALE_EQUALS (new_scale, gimp_zoom_model_get_factor (shell->zoom)))
return;
x = shell->disp_width / 2;
y = shell->disp_height / 2;
/* Center on the mouse position instead of the display center,
* if one of the following conditions is fulfilled:
*
* (1) there's no current event (the action was triggered by an
* input controller)
* (2) the event originates from the canvas (a scroll event)
* (3) the event originates from the shell (a key press event)
*
* Basically the only situation where we don't want to center on
* mouse position is if the action is being called from a menu.
*/
event = gtk_get_current_event ();
if (! event ||
gtk_get_event_widget (event) == shell->canvas ||
gtk_get_event_widget (event) == GTK_WIDGET (shell))
{
gtk_widget_get_pointer (shell->canvas, &x, &y);
}
gimp_display_shell_scale_to (shell, zoom_type, new_scale, x, y);
}
/**
* gimp_display_shell_scale_to:
* @shell: the #GimpDisplayShell
* @zoom_type: whether to zoom in, out or to a specified scale
* @scale: ignored unless @zoom_type == %GIMP_ZOOM_TO
* @x: x screen coordinate
* @y: y screen coordinate
*
* This function changes the scale (zoom ratio) of the display shell.
* It either zooms in / out one step (%GIMP_ZOOM_IN / %GIMP_ZOOM_OUT)
* or sets the scale to the zoom ratio passed as @scale (%GIMP_ZOOM_TO).
*
* The display offsets are adjusted so that the point specified by @x
* and @y doesn't change it's position on screen (if possible). You
* would typically pass either the display center or the mouse
* position here.
**/
void
gimp_display_shell_scale_to (GimpDisplayShell *shell,
GimpZoomType zoom_type,
gdouble scale,
gdouble x,
gdouble y)
{
gdouble current;
gdouble offset_x;
gdouble offset_y;
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
if (! shell->display)
return;
current = gimp_zoom_model_get_factor (shell->zoom);
offset_x = shell->offset_x + x;
offset_y = shell->offset_y + y;
offset_x /= current;
offset_y /= current;
if (zoom_type != GIMP_ZOOM_TO)
scale = gimp_zoom_model_zoom_step (zoom_type, current);
offset_x *= scale;
offset_y *= scale;
gimp_display_shell_scale_by_values (shell, scale,
offset_x - x, offset_y - y,
shell->display->config->resize_windows_on_zoom);
}
/**
* gimp_display_shell_scale_fit_in:
* @shell: the #GimpDisplayShell
*
* Sets the scale such that the entire image precisely fits in the display
* area.
**/
void
gimp_display_shell_scale_fit_in (GimpDisplayShell *shell)
{
GimpImage *image;
gint image_width;
gint image_height;
gdouble xres;
gdouble yres;
gdouble zoom_factor;
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
image = shell->display->image;
image_width = gimp_image_get_width (image);
image_height = gimp_image_get_height (image);
gimp_image_get_resolution (image, &xres, &yres);
if (! shell->dot_for_dot)
{
image_width = ROUND (image_width * shell->monitor_xres / xres);
image_height = ROUND (image_height * shell->monitor_yres / yres);
}
zoom_factor = MIN ((gdouble) shell->disp_width / (gdouble) image_width,
(gdouble) shell->disp_height / (gdouble) image_height);
gimp_display_shell_scale (shell, GIMP_ZOOM_TO, zoom_factor);
}
/**
* gimp_display_shell_scale_fill:
* @shell: the #GimpDisplayShell
*
* Sets the scale such that the entire display area is precisely filled by the
* image.
**/
void
gimp_display_shell_scale_fill (GimpDisplayShell *shell)
{
GimpImage *image;
gint image_width;
gint image_height;
gdouble xres;
gdouble yres;
gdouble zoom_factor;
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
image = shell->display->image;
image_width = gimp_image_get_width (image);
image_height = gimp_image_get_height (image);
gimp_image_get_resolution (image, &xres, &yres);
if (! shell->dot_for_dot)
{
image_width = ROUND (image_width * shell->monitor_xres / xres);
image_height = ROUND (image_height * shell->monitor_yres / yres);
}
zoom_factor = MAX ((gdouble) shell->disp_width / (gdouble) image_width,
(gdouble) shell->disp_height / (gdouble) image_height);
gimp_display_shell_scale (shell, GIMP_ZOOM_TO, zoom_factor);
}
/**
* 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
* accomodate 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)
{
guint now;
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;
/* remember the current scale and offsets to allow reverting the scaling */
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;
/* 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, TRUE);
/* re-enable the active tool */
gimp_display_shell_resume (shell);
}
/**
* gimp_display_shell_scale_shrink_wrap:
* @shell: the #GimpDisplayShell
*
* Convenience function with the same functionality as
* gimp_display_shell_scale_resize(@shell, TRUE, TRUE).
**/
void
gimp_display_shell_scale_shrink_wrap (GimpDisplayShell *shell)
{
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
gimp_display_shell_scale_resize (shell, TRUE, TRUE);
}
/**
* gimp_display_shell_scale_resize:
* @shell: the #GimpDisplayShell
* @resize_window: whether the display window should be resized
* @redisplay: whether the display window should be redrawn
*
* Function commonly called after a change in display scale to make the changes
* visible to the user. If @resize_window is %TRUE then the display window is
* resized to accomodate the display image as per
* gimp_display_shell_shrink_wrap().
**/
void
gimp_display_shell_scale_resize (GimpDisplayShell *shell,
gboolean resize_window,
gboolean redisplay)
{
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
/* freeze the active tool */
gimp_display_shell_pause (shell);
if (resize_window)
gimp_display_shell_shrink_wrap (shell);
gimp_display_shell_scroll_clamp_offsets (shell);
gimp_display_shell_scale_setup (shell);
gimp_display_shell_scaled (shell);
if (resize_window || redisplay)
gimp_display_shell_expose_full (shell);
/* re-enable the active tool */
gimp_display_shell_resume (shell);
}
/**
* 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 *hbox;
GtkWidget *table;
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 = shell->display->image;
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",
GTK_STOCK_ZOOM_100,
_("Select Zoom Ratio"),
GTK_WIDGET (shell),
gimp_standard_help_func,
GIMP_HELP_VIEW_ZOOM_OTHER,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OK, GTK_RESPONSE_OK,
NULL);
gtk_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);
gtk_window_set_transient_for (GTK_WINDOW (shell->scale_dialog),
GTK_WINDOW (shell));
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);
table = gtk_table_new (2, 2, FALSE);
gtk_container_set_border_width (GTK_CONTAINER (table), 12);
gtk_table_set_col_spacings (GTK_TABLE (table), 6);
gtk_table_set_row_spacings (GTK_TABLE (table), 6);
gtk_container_add (GTK_CONTAINER (GTK_DIALOG (shell->scale_dialog)->vbox),
table);
gtk_widget_show (table);
row = 0;
hbox = gtk_hbox_new (FALSE, 6);
gimp_table_attach_aligned (GTK_TABLE (table), 0, row++,
_("Zoom ratio:"), 0.0, 0.5,
hbox, 1, FALSE);
gimp_zoom_model_get_fraction (data->model, &num, &denom);
spin = gimp_spin_button_new (&data->num_adj,
num, 1, 256,
1, 8, 1, 1, 0);
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);
spin = gimp_spin_button_new (&data->denom_adj,
denom, 1, 256,
1, 8, 1, 1, 0);
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_hbox_new (FALSE, 6);
gimp_table_attach_aligned (GTK_TABLE (table), 0, row++,
_("Zoom:"), 0.0, 0.5,
hbox, 1, FALSE);
spin = gimp_spin_button_new (&data->scale_adj,
fabs (shell->other_scale) * 100,
100.0 / 256.0, 25600.0,
10, 50, 0, 1, 2);
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);
}
/* private functions */
static void
gimp_display_shell_scale_dialog_response (GtkWidget *widget,
gint response_id,
ScaleDialogData *dialog)
{
if (response_id == GTK_RESPONSE_OK)
{
gdouble scale;
scale = gtk_adjustment_get_value (GTK_ADJUSTMENT (dialog->scale_adj));
gimp_display_shell_scale (dialog->shell, GIMP_ZOOM_TO, scale / 100.0);
}
else
{
/* need to emit "scaled" to get the menu updated */
gimp_display_shell_scaled (dialog->shell);
}
dialog->shell->other_scale = - fabs (dialog->shell->other_scale);
gtk_widget_destroy (dialog->shell->scale_dialog);
}
static void
gimp_display_shell_scale_dialog_free (ScaleDialogData *dialog)
{
g_slice_free (ScaleDialogData, dialog);
}
static void
update_zoom_values (GtkAdjustment *adj,
ScaleDialogData *dialog)
{
gint num, denom;
gdouble scale;
g_signal_handlers_block_by_func (GTK_ADJUSTMENT (dialog->scale_adj),
G_CALLBACK (update_zoom_values),
dialog);
g_signal_handlers_block_by_func (GTK_ADJUSTMENT (dialog->num_adj),
G_CALLBACK (update_zoom_values),
dialog);
g_signal_handlers_block_by_func (GTK_ADJUSTMENT (dialog->denom_adj),
G_CALLBACK (update_zoom_values),
dialog);
if (GTK_OBJECT (adj) == dialog->scale_adj)
{
scale = gtk_adjustment_get_value (GTK_ADJUSTMENT (dialog->scale_adj));
gimp_zoom_model_zoom (dialog->model, GIMP_ZOOM_TO, scale / 100.0);
gimp_zoom_model_get_fraction (dialog->model, &num, &denom);
gtk_adjustment_set_value (GTK_ADJUSTMENT (dialog->num_adj), num);
gtk_adjustment_set_value (GTK_ADJUSTMENT (dialog->denom_adj), denom);
}
else /* fraction adjustments */
{
scale = (gtk_adjustment_get_value (GTK_ADJUSTMENT (dialog->num_adj)) /
gtk_adjustment_get_value (GTK_ADJUSTMENT (dialog->denom_adj)));
gtk_adjustment_set_value (GTK_ADJUSTMENT (dialog->scale_adj),
scale * 100);
}
g_signal_handlers_unblock_by_func (GTK_ADJUSTMENT (dialog->scale_adj),
G_CALLBACK (update_zoom_values),
dialog);
g_signal_handlers_unblock_by_func (GTK_ADJUSTMENT (dialog->num_adj),
G_CALLBACK (update_zoom_values),
dialog);
g_signal_handlers_unblock_by_func (GTK_ADJUSTMENT (dialog->denom_adj),
G_CALLBACK (update_zoom_values),
dialog);
}
/* scale image coord to realworld units (cm, inches, pixels)
*
* 27/Feb/1999 I tried inlining this, but the result was slightly
* slower (poorer cache locality, probably) -- austin
*/
static gdouble
img2real (GimpDisplayShell *shell,
gboolean xdir,
gdouble len)
{
gdouble xres;
gdouble yres;
gdouble res;
if (shell->unit == GIMP_UNIT_PIXEL)
return len;
gimp_image_get_resolution (shell->display->image, &xres, &yres);
if (xdir)
res = xres;
else
res = yres;
return len * _gimp_unit_get_factor (shell->display->gimp, shell->unit) / res;
}