gimp/app/display/gimpdisplayshell-scale.c
Michael Natterer 6cf34005af include the new "paint-funcs/paint-funcs-types.h".
2001-11-28  Michael Natterer  <mitch@gimp.org>

	* app/base/base-types.h: include the new
	"paint-funcs/paint-funcs-types.h".

	* app/paint-funcs/Makefile.am
	* app/paint-funcs/paint-funcs-types.h: new file. Includes
	"base/base-types.h".

	* app/paint-funcs/paint-funcs.[ch]: removed the enums here,
	include "paint-funcs-types.h".

	* app/widgets/widgets-types.h: include "display/display-types.h"

	* app/display/display-types.h: include "widgets/widgets-types.h".

	* app/tools/tools-types.h: include "display/display-types.h"

	* app/gui/gui-types.h: include "tools/tools-types.h".

	The order of namespaces/dependencies should be (but is not):

	(base, paint-funcs) -> (core, file, xcf, pdb) ->
	(widgets, display) -> tools -> gui

	* app/path.c: include "tools/tools-types.h".

	* app/core/Makefile.am
	* app/core/gimpimage-guides.[ch]
	* app/core/gimpimage-merge.[ch]
	* app/core/gimpimage-resize.[ch]
	* app/core/gimpimage-scale.[ch]: new files.

	* app/core/gimpimage.[ch]: removed the stuff which is in the new
	files. Reordered all functions in both the .h and .c files,
	commented the groups of functions.

	* app/core/gimpcontainer.c: create the handler_id using a counter,
	not the address of a pointer, because the address *may* be the
	same twice, added debugging output.

	* app/core/gimpviewable.[ch]: added primitive support for getting
	a preview GdkPixbuf.

	* app/nav_window.c
	* app/undo.c
	* app/undo_history.c
	* app/core/gimpimage-duplicate.c
	* app/core/gimpimage-mask.[ch]
	* app/display/gimpdisplay.c
	* app/display/gimpdisplayshell-callbacks.c
	* app/display/gimpdisplayshell-dnd.c
	* app/display/gimpdisplayshell-render.c
	* app/display/gimpdisplayshell-scale.c
	* app/display/gimpdisplayshell-scroll.c
	* app/gui/image-commands.c
	* app/gui/info-window.c
	* app/gui/layers-commands.c
	* app/gui/palette-import-dialog.c
	* app/tools/gimpbycolorselecttool.c
	* app/tools/gimpeditselectiontool.c
	* app/tools/gimpmeasuretool.c
	* app/tools/gimpmovetool.c
	* app/widgets/gimpcontainerview-utils.c
	* app/xcf/xcf-load.c: changed accordingly, some cleanup.

	* tools/pdbgen/pdb/guides.pdb
	* tools/pdbgen/pdb/image.pdb: changed accordingly, reordered functions.

	* app/plug_in.c: set the labels of the "Repeat" and "Re-Show" menu
	items to the name of the last plug-in (Fixes #50986).

	* app/display/gimpdisplayshell.[ch]: set the labels of "Undo" and
	"Redo" to the resp. undo names. Much simplified the WM icon stuff
	by removing most code and using gimp_viewable_get_new_preview_pixbuf().

	* app/widgets/gimpbrushfactoryview.c: forgot to assign the GQuark
	returned by gimp_container_add_handler().

	* app/pdb/guides_cmds.c
	* app/pdb/image_cmds.c
	* libgimp/gimpimage_pdb.[ch]: regenerated.
2001-11-28 17:51:06 +00:00

441 lines
12 KiB
C

/* The GIMP -- an 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 "libgimpbase/gimpbase.h"
#include "display-types.h"
#include "core/gimpimage.h"
#include "tools/tools-types.h"
#include "tools/tool_manager.h"
#include "gimpdisplay.h"
#include "gimpdisplay-foreach.h"
#include "gimpdisplayshell.h"
#include "gimpdisplayshell-scale.h"
#include "gimpdisplayshell-scroll.h"
#include "gimprc.h"
#include "nav_window.h"
/* local function prototypes */
static gdouble img2real (GimpDisplay *gdisp,
gboolean xdir,
gdouble a);
/* public functions */
void
gimp_display_shell_scale_setup (GimpDisplayShell *shell)
{
GtkRuler *hruler;
GtkRuler *vruler;
gfloat sx, sy;
gfloat stepx, stepy;
gint image_width, image_height;
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
image_width = shell->gdisp->gimage->width;
image_height = shell->gdisp->gimage->height;
sx = SCALEX (shell->gdisp, image_width);
sy = SCALEY (shell->gdisp, image_height);
stepx = SCALEFACTOR_X (shell->gdisp);
stepy = SCALEFACTOR_Y (shell->gdisp);
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 = stepx;
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 = stepy;
gtk_adjustment_changed (shell->hsbdata);
gtk_adjustment_changed (shell->vsbdata);
hruler = GTK_RULER (shell->hrule);
vruler = GTK_RULER (shell->vrule);
hruler->lower = 0;
hruler->upper = img2real (shell->gdisp, TRUE,
FUNSCALEX (shell->gdisp, shell->disp_width));
hruler->max_size = img2real (shell->gdisp, TRUE,
MAX (image_width, image_height));
vruler->lower = 0;
vruler->upper = img2real (shell->gdisp, FALSE,
FUNSCALEY (shell->gdisp, shell->disp_height));
vruler->max_size = img2real (shell->gdisp, FALSE,
MAX (image_width, image_height));
if (sx < shell->disp_width)
{
shell->disp_xoffset = (shell->disp_width - sx) / 2;
hruler->lower -= img2real (shell->gdisp, TRUE,
FUNSCALEX (shell->gdisp,
(gdouble) shell->disp_xoffset));
hruler->upper -= img2real (shell->gdisp, TRUE,
FUNSCALEX (shell->gdisp,
(gdouble) shell->disp_xoffset));
}
else
{
shell->disp_xoffset = 0;
hruler->lower += img2real (shell->gdisp, TRUE,
FUNSCALEX (shell->gdisp,
(gdouble) shell->offset_x));
hruler->upper += img2real (shell->gdisp, TRUE,
FUNSCALEX (shell->gdisp,
(gdouble) shell->offset_x));
}
if (sy < shell->disp_height)
{
shell->disp_yoffset = (shell->disp_height - sy) / 2;
vruler->lower -= img2real (shell->gdisp, FALSE,
FUNSCALEY (shell->gdisp,
(gdouble) shell->disp_yoffset));
vruler->upper -= img2real (shell->gdisp, FALSE,
FUNSCALEY (shell->gdisp,
(gdouble) shell->disp_yoffset));
}
else
{
shell->disp_yoffset = 0;
vruler->lower += img2real (shell->gdisp, FALSE,
FUNSCALEY (shell->gdisp,
(gdouble) shell->offset_y));
vruler->upper += img2real (shell->gdisp, FALSE,
FUNSCALEY (shell->gdisp,
(gdouble) shell->offset_y));
}
gtk_widget_queue_draw (GTK_WIDGET (hruler));
gtk_widget_queue_draw (GTK_WIDGET (vruler));
nav_dialog_update_window_marker (shell->nav_dialog);
if (shell->nav_popup)
nav_dialog_update_window_marker (shell->nav_popup);
#if 0
g_print ("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
}
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->gdisp->dot_for_dot)
{
shell->gdisp->dot_for_dot = dot_for_dot;
gimp_display_shell_resize_cursor_label (shell);
gimp_display_shell_scale_resize (shell,
gimprc.resize_windows_on_zoom, TRUE);
}
}
void
gimp_display_shell_scale (GimpDisplayShell *shell,
GimpZoomType zoom_type)
{
guchar scalesrc, scaledest;
gdouble offset_x, offset_y;
glong sx, sy;
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
/* user zoom control, so resolution versions not needed -- austin */
scalesrc = SCALESRC (shell->gdisp);
scaledest = SCALEDEST (shell->gdisp);
offset_x = shell->offset_x + (shell->disp_width / 2.0);
offset_y = shell->offset_y + (shell->disp_height / 2.0);
offset_x *= ((double) scalesrc / (double) scaledest);
offset_y *= ((double) scalesrc / (double) scaledest);
switch (zoom_type)
{
case GIMP_ZOOM_IN:
if (scalesrc > 1)
scalesrc--;
else
if (scaledest < 0x10)
scaledest++;
else
return;
break;
case GIMP_ZOOM_OUT:
if (scaledest > 1)
scaledest--;
else
if (scalesrc < 0x10)
scalesrc++;
else
return;
break;
default:
scalesrc = zoom_type % 100;
if (scalesrc < 1)
scalesrc = 1;
else if (scalesrc > 0x10)
scalesrc = 0x10;
scaledest = zoom_type / 100;
if (scaledest < 1)
scaledest = 1;
else if (scaledest > 0x10)
scaledest = 0x10;
break;
}
sx = (shell->gdisp->gimage->width * scaledest) / scalesrc;
sy = (shell->gdisp->gimage->height * scaledest) / scalesrc;
/* The slider value is a short, so make sure we are within its
* range. If we are trying to scale past it, then stop the scale
*/
if (sx < 0xffff && sy < 0xffff)
{
shell->gdisp->scale = (scaledest << 8) + scalesrc;
/* set the offsets */
offset_x *= ((gdouble) scaledest / (gdouble) scalesrc);
offset_y *= ((gdouble) scaledest / (gdouble) scalesrc);
shell->offset_x = (gint) (offset_x - (shell->disp_width / 2));
shell->offset_y = (gint) (offset_y - (shell->disp_height / 2));
/* resize the display */
gimp_display_shell_scale_resize (shell, gimprc.resize_windows_on_zoom,
TRUE);
}
}
void
gimp_display_shell_scale_fit (GimpDisplayShell *shell)
{
gint image_width;
gint image_height;
gdouble zoom_x;
gdouble zoom_y;
gdouble zoom_factor;
gdouble zoom_delta;
gdouble min_zoom_delta = G_MAXFLOAT;
gint scalesrc = 1;
gint scaledest = 1;
gint i;
gint best_i = 0x10;
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
image_width = shell->gdisp->gimage->width;
image_height = shell->gdisp->gimage->height;
if (! shell->gdisp->dot_for_dot)
{
image_width = ROUND (image_width *
gimprc.monitor_xres /
shell->gdisp->gimage->xresolution);
image_height = ROUND (image_height *
gimprc.monitor_yres /
shell->gdisp->gimage->yresolution);
}
zoom_x = (gdouble) shell->disp_width / (gdouble) image_width;
zoom_y = (gdouble) shell->disp_height / (gdouble) image_height;
if ((gdouble) image_height * zoom_x <= (gdouble) shell->disp_height)
{
zoom_factor = zoom_x;
}
else
{
zoom_factor = zoom_y;
}
if (zoom_factor < 1.0)
{
for (i = 0x10; i > 0; i--)
{
scalesrc = i;
scaledest = floor ((gdouble) scalesrc * zoom_factor);
if (scaledest < 0x1)
{
scaledest = 0x1;
}
zoom_delta = ABS ((gdouble) scaledest / (gdouble) scalesrc -
zoom_factor);
if (zoom_delta <= min_zoom_delta)
{
min_zoom_delta = zoom_delta;
best_i = i;
}
}
scalesrc = best_i;
scaledest = floor ((gdouble) scalesrc * zoom_factor);
if (scaledest < 0x1)
{
scaledest = 0x1;
}
}
else
{
for (i = 0x10; i > 0; i--)
{
scaledest = i;
scalesrc = ceil ((gdouble) scaledest / zoom_factor);
if (scalesrc < 0x1)
{
scalesrc = 0x1;
}
zoom_delta = ABS ((gdouble) scaledest / (gdouble) scalesrc -
zoom_factor);
if (zoom_delta <= min_zoom_delta)
{
min_zoom_delta = zoom_delta;
best_i = i;
}
}
scaledest = best_i;
scalesrc = ceil ((gdouble) scaledest / zoom_factor);
if (scalesrc < 0x1)
{
scalesrc = 0x1;
}
}
shell->gdisp->scale = (scaledest << 8) + scalesrc;
shell->offset_x = 0;
shell->offset_y = 0;
gimp_display_shell_scale_resize (shell, FALSE, TRUE);
}
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 */
tool_manager_control_active (shell->gdisp->gimage->gimp, PAUSE,
shell->gdisp);
if (resize_window)
gimp_display_shell_shrink_wrap (shell);
gimp_display_shell_scroll_clamp_offsets (shell);
gimp_display_shell_scale_setup (shell);
if (resize_window || redisplay)
{
gimp_display_shell_expose_full (shell);
gdisplays_flush ();
/* title may have changed if it includes the zoom ratio */
gimp_display_shell_update_title (shell);
}
/* re-enable the active tool */
tool_manager_control_active (shell->gdisp->gimage->gimp, RESUME,
shell->gdisp);
}
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);
}
/* private functions */
/* 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 (GimpDisplay *gdisp,
gboolean xdir,
gdouble a)
{
gdouble res;
if (gdisp->dot_for_dot)
return a;
if (xdir)
res = gdisp->gimage->xresolution;
else
res = gdisp->gimage->yresolution;
return a * gimp_unit_get_factor (gdisp->gimage->unit) / res;
}