gimp/app/display/gimpnavigationeditor.c
Michael Natterer d162376d47 app/display/Makefile.am app/display/gimpdisplay-callbacks.[ch]
2001-11-01  Michael Natterer  <mitch@gimp.org>

	* app/display/Makefile.am
	* app/display/gimpdisplay-callbacks.[ch]
	* app/display/gimpdisplay-render.[ch]
	* app/display/gimpdisplay-scale.[ch]
	* app/display/gimpdisplay-scroll.[ch]: removed and added as
	gimpdisplayshell-foo.[ch] because they are all methods of the
	shell.

	* app/display/gimpdisplay.[ch]
	* app/display/gimpdisplayshell.[ch]: moved the "offset" and "size"
	variables from GimpDisplay to GimpDisplayShell. GimpDisplay
	should know nothing about screen coordinates.

	The gdisplay_[un]transform_foo() methods are still part of
	GimpDisplay but will be moved to GimpDisplayShell as soon as the
	tools' vitrual functions speak in image coordinates instead of
	GdkEvents.

	* app/display/gimpdisplayshell-callbacks.[ch]: prefixed all
	functions with gimp_display_shell_*. Moved some stuff to a
	"realize" callback File still has to be renamed.

	* app/display/gimpdisplay-foreach.[ch]: removed
	gdisplays_shrink_wrap().

	* app/gui/menus.c
	* app/gui/view-commands.[ch]
	* app/display/gimpdisplayshell-scale.[ch]: implemented "Zoom to
	Fit Window" function (#57670).

	* app/nav_window.c
	* app/display/gimpdisplay-handlers.c
	* app/display/gimpdisplayshell-render.[ch]
	* app/display/gimpdisplayshell-scale.[ch]
	* app/display/gimpdisplayshell-scroll.[ch]
	* app/gui/colormap-dialog.c
	* app/gui/gui.c
	* app/gui/preferences-dialog.c
	* app/tools/gimpmagnifytool.c
	* app/tools/gimpmovetool.c
	* app/widgets/gimppreview.c: changed according to variable
	and filename changes.

	* app/tools/tool_manager.c: tool_manager_select_tool(): send the
	active tool a "HALT" command before selecting the new one. Fixes
	stale tool dialogs which were there because some other hack was
	removed (This is IMHO the right place to shut down the active
	tool).

	* app/tools/gimpcroptool.c: don't shrink wrap after cropping but
	let gimprc.allow_resize_windows decide.

	* app/tools/gimpselectiontool.c: gimage_mask_value() takes image,
	not screen coordinates. A good example of how braindead it is to
	pass GdkEvents to tools :-) Fixes incorrect cursor and oper
	update of the selection tools.

	* app/tools/gimptransformtool.c
	* app/undo.c: removed (#if 0 for now) some strange code which did
	manual exposing of GimpDisplayShell areas. This was definitely a
	hack and should not be there given the image emits correct
	"update" signals.
2001-11-02 09:31:21 +00:00

1720 lines
44 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 <gdk/gdkkeysyms.h>
#include "libgimpmath/gimpmath.h"
#include "libgimpwidgets/gimpwidgets.h"
#include "widgets/widgets-types.h"
#include "base/temp-buf.h"
#include "core/gimp.h"
#include "core/gimpcontainer.h"
#include "core/gimpcontext.h"
#include "core/gimpimage.h"
#include "core/gimplist.h"
#include "display/gimpdisplay.h"
#include "display/gimpdisplay-foreach.h"
#include "display/gimpdisplayshell.h"
#include "display/gimpdisplayshell-scroll.h"
#include "display/gimpdisplayshell-scale.h"
#include "widgets/gimpnavigationpreview.h"
#include "app_procs.h"
#include "nav_window.h"
#include "app_procs.h"
#include "gimprc.h"
#include "libgimp/gimpintl.h"
#include "pixmaps/zoom_in.xpm"
#include "pixmaps/zoom_out.xpm"
#define PREVIEW_MASK GDK_EXPOSURE_MASK | \
GDK_BUTTON_PRESS_MASK | \
GDK_KEY_PRESS_MASK | \
GDK_KEY_RELEASE_MASK | \
GDK_POINTER_MOTION_MASK
/* Navigation preview sizes */
#define NAV_PREVIEW_WIDTH 112
#define NAV_PREVIEW_HEIGHT 112
#define BORDER_PEN_WIDTH 3
#define MAX_SCALE_BUF 20
typedef enum
{
NAV_WINDOW,
NAV_POPUP
} NavWinType;
struct _NavigationDialog
{
NavWinType ptype;
GtkWidget *shell;
GtkWidget *new_preview;
GtkWidget *preview_frame;
GtkWidget *zoom_label;
GtkObject *zoom_adjustment;
GtkWidget *preview;
GimpDisplay *gdisp; /* I'm not happy 'bout this one */
GdkGC *gc;
gint dispx; /* x pos of top left corner of display area */
gint dispy; /* y pos of top left corner of display area */
gint dispwidth; /* width of display area */
gint dispheight; /* height of display area */
gboolean sq_grabbed; /* In the process of moving the preview square */
gint motion_offsetx;
gint motion_offsety;
gint pwidth; /* real preview width */
gint pheight; /* real preview height */
gint imagewidth; /* width of the real image */
gint imageheight; /* height of real image */
gdouble ratio;
gint nav_preview_width;
gint nav_preview_height;
gboolean block_adj_sig;
gboolean frozen; /* Has the dialog been frozen ? */
guint idle_id;
};
static NavigationDialog * nav_dialog_new (GimpDisplay *gdisp,
NavWinType ptype);
static gchar * nav_dialog_title (GimpDisplay *gdisp);
static GtkWidget * nav_create_button_area (NavigationDialog *nav_dialog);
static void nav_dialog_close_callback (GtkWidget *widget,
gpointer data);
static void nav_dialog_disp_area (NavigationDialog *nav_dialog,
GimpDisplay *gdisp);
static void nav_dialog_draw_sqr (NavigationDialog *nav_dialog,
gboolean undraw,
gint x,
gint y,
gint w,
gint h);
static gboolean nav_dialog_preview_events (GtkWidget *widget,
GdkEvent *event,
gpointer data);
static void nav_dialog_idle_update_preview (NavigationDialog *nav_dialog);
static void nav_dialog_update_preview (NavigationDialog *nav_dialog);
static void nav_dialog_update_preview_blank (NavigationDialog *nav_dialog);
static void create_preview_widget (NavigationDialog *nav_dialog);
static void set_size_data (NavigationDialog *nav_dialog);
static void nav_image_need_update (GimpImage *gimage,
gpointer data);
static void nav_dialog_display_changed (GimpContext *context,
GimpDisplay *gdisp,
gpointer data);
static GimpDisplay * nav_dialog_get_gdisp (void);
static void nav_dialog_grab_pointer (NavigationDialog *nav_dialog,
GtkWidget *widget);
static void update_zoom_label (NavigationDialog *nav_dialog);
static void update_zoom_adjustment (NavigationDialog *nav_dialog);
static NavigationDialog *nav_window_auto = NULL;
/* public functions */
static void
nav_dialog_marker_changed (GimpNavigationPreview *nav_preview,
gint x,
gint y,
NavigationDialog *nav_dialog)
{
GimpDisplayShell *shell;
gdouble xratio;
gdouble yratio;
gint xoffset;
gint yoffset;
shell = GIMP_DISPLAY_SHELL (nav_dialog->gdisp->shell);
xratio = SCALEFACTOR_X (nav_dialog->gdisp);
yratio = SCALEFACTOR_Y (nav_dialog->gdisp);
xoffset = x * xratio - shell->offset_x;
yoffset = y * yratio - shell->offset_y;
gimp_display_shell_scroll (shell, xoffset, yoffset);
}
static void
nav_dialog_zoom (GimpNavigationPreview *nav_preview,
GimpZoomType direction,
NavigationDialog *nav_dialog)
{
GimpDisplayShell *shell;
shell = GIMP_DISPLAY_SHELL (nav_dialog->gdisp->shell);
gimp_display_shell_scale (shell, direction);
}
static void
nav_dialog_scroll (GimpNavigationPreview *nav_preview,
GdkScrollDirection direction,
NavigationDialog *nav_dialog)
{
GimpDisplayShell *shell;
GtkAdjustment *adj = NULL;
gdouble value;
shell = GIMP_DISPLAY_SHELL (nav_dialog->gdisp->shell);
g_print ("nav_dialog_scroll(%d)\n", direction);
switch (direction)
{
case GDK_SCROLL_LEFT:
case GDK_SCROLL_RIGHT:
adj = shell->hsbdata;
break;
case GDK_SCROLL_UP:
case GDK_SCROLL_DOWN:
adj = shell->vsbdata;
break;
}
g_assert (adj != NULL);
value = adj->value;
switch (direction)
{
case GDK_SCROLL_LEFT:
case GDK_SCROLL_UP:
value -= adj->page_increment / 2;
break;
case GDK_SCROLL_RIGHT:
case GDK_SCROLL_DOWN:
value += adj->page_increment / 2;
break;
}
value = CLAMP (value, adj->lower, adj->upper - adj->page_size);
gtk_adjustment_set_value (adj, value);
}
NavigationDialog *
nav_dialog_create (GimpDisplay *gdisp)
{
NavigationDialog *nav_dialog;
GtkWidget *button_area;
GtkWidget *abox;
gchar *title;
title = nav_dialog_title (gdisp);
nav_dialog = nav_dialog_new (gdisp, NAV_WINDOW);
nav_dialog->shell = gimp_dialog_new (title, "navigation_dialog",
gimp_standard_help_func,
"dialogs/navigation_window.html",
GTK_WIN_POS_MOUSE,
FALSE, TRUE, TRUE,
"_delete_event_",
nav_dialog_close_callback,
nav_dialog, NULL, NULL, TRUE, TRUE,
NULL);
g_free (title);
gtk_dialog_set_has_separator (GTK_DIALOG (nav_dialog->shell), FALSE);
gtk_widget_hide (GTK_DIALOG (nav_dialog->shell)->action_area);
g_object_weak_ref (G_OBJECT (nav_dialog->shell),
(GWeakNotify) g_free,
nav_dialog);
abox = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (nav_dialog->shell)->vbox), abox,
TRUE, TRUE, 0);
gtk_widget_show (abox);
nav_dialog->preview_frame = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (nav_dialog->preview_frame),
GTK_SHADOW_IN);
gtk_container_add (GTK_CONTAINER (abox), nav_dialog->preview_frame);
gtk_widget_show (nav_dialog->preview_frame);
create_preview_widget (nav_dialog);
{
GtkWidget *frame;
GtkWidget *preview;
abox = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (nav_dialog->shell)->vbox), abox,
TRUE, TRUE, 0);
gtk_widget_show (abox);
frame = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
gtk_container_add (GTK_CONTAINER (abox), frame);
gtk_widget_show (frame);
preview = gimp_navigation_preview_new (gdisp->gimage,
gimprc.nav_preview_size);
gtk_container_add (GTK_CONTAINER (frame), preview);
gtk_widget_show (preview);
g_signal_connect (G_OBJECT (preview), "marker_changed",
G_CALLBACK (nav_dialog_marker_changed),
nav_dialog);
g_signal_connect (G_OBJECT (preview), "zoom",
G_CALLBACK (nav_dialog_zoom),
nav_dialog);
g_signal_connect (G_OBJECT (preview), "scroll",
G_CALLBACK (nav_dialog_scroll),
nav_dialog);
nav_dialog->new_preview = preview;
}
button_area = nav_create_button_area (nav_dialog);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (nav_dialog->shell)->vbox),
button_area, FALSE, FALSE, 0);
gtk_widget_show (button_area);
if (! g_object_get_data (G_OBJECT (gdisp->gimage), "nav_handlers_installed"))
{
g_signal_connect (G_OBJECT (gdisp->gimage), "dirty",
G_CALLBACK (nav_image_need_update),
nav_dialog);
g_signal_connect (G_OBJECT (gdisp->gimage), "clean",
G_CALLBACK (nav_image_need_update),
nav_dialog);
g_object_set_data (G_OBJECT (gdisp->gimage), "nav_handlers_installed",
nav_dialog);
}
return nav_dialog;
}
void
nav_dialog_free (GimpDisplay *del_gdisp,
NavigationDialog *nav_dialog)
{
/* So this functions works both ways..
* it will come in here with nav_dialog == null
* if the auto mode is on...
*/
if (! nav_dialog)
{
if (nav_window_auto != NULL)
{
GimpDisplay *gdisp;
nav_dialog = nav_window_auto;
/* Only freeze if we are displaying the image we have deleted */
if (nav_dialog->gdisp != del_gdisp)
return;
if (nav_dialog->idle_id)
{
g_source_remove (nav_dialog->idle_id);
nav_dialog->idle_id = 0;
}
gdisp = nav_dialog_get_gdisp ();
if (gdisp)
{
nav_dialog_display_changed (NULL, gdisp, nav_window_auto);
}
else
{
/* Clear window and freeze */
nav_dialog->frozen = TRUE;
nav_dialog_update_preview_blank (nav_window_auto);
gtk_window_set_title (GTK_WINDOW (nav_window_auto->shell),
_("Navigation: No Image"));
gtk_widget_set_sensitive (nav_window_auto->shell, FALSE);
nav_window_auto->gdisp = NULL;
gtk_widget_hide (GTK_WIDGET (nav_window_auto->shell));
}
}
return;
}
if (nav_dialog->idle_id)
{
g_source_remove (nav_dialog->idle_id);
nav_dialog->idle_id = 0;
}
gtk_widget_destroy (nav_dialog->shell);
}
void
nav_dialog_popup (NavigationDialog *nav_dialog)
{
if (! nav_dialog)
return;
if (! GTK_WIDGET_VISIBLE (nav_dialog->shell))
{
gtk_widget_show (nav_dialog->shell);
nav_dialog_idle_update_preview (nav_dialog);
}
gdk_window_raise (nav_dialog->shell->window);
}
void
nav_dialog_follow_auto (void)
{
GimpContext *context;
GimpDisplay *gdisp;
context = gimp_get_user_context (the_gimp);
gdisp = gimp_context_get_display (context);
if (! gdisp)
return;
if (! nav_window_auto)
{
nav_window_auto = nav_dialog_create (gdisp);
g_signal_connect (G_OBJECT (context), "display_changed",
G_CALLBACK (nav_dialog_display_changed),
nav_window_auto);
}
nav_dialog_popup (nav_window_auto);
gtk_widget_set_sensitive (nav_window_auto->shell, TRUE);
nav_window_auto->frozen = FALSE;
}
void
nav_dialog_update_window_marker (NavigationDialog *nav_dialog)
{
/* So this functions works both ways..
* it will come in here with info_win == null
* if the auto mode is on...
*/
if (! nav_dialog && nav_window_auto)
{
nav_dialog = nav_window_auto;
if (nav_dialog->frozen)
return;
nav_dialog_update_window_marker (nav_window_auto);
return;
}
else if (! nav_dialog)
{
return;
}
if (! GTK_WIDGET_VISIBLE (nav_dialog->shell))
return;
update_zoom_label (nav_dialog);
update_zoom_adjustment (nav_dialog);
/* Undraw old size */
nav_dialog_draw_sqr (nav_dialog,
FALSE,
nav_dialog->dispx, nav_dialog->dispy,
nav_dialog->dispwidth, nav_dialog->dispheight);
/* Update to new size */
nav_dialog_disp_area (nav_dialog, nav_dialog->gdisp);
/* and redraw */
nav_dialog_draw_sqr (nav_dialog,
FALSE,
nav_dialog->dispx, nav_dialog->dispy,
nav_dialog->dispwidth, nav_dialog->dispheight);
}
void
nav_dialog_preview_resized (NavigationDialog *nav_dialog)
{
if (! nav_dialog)
return;
/* force regeneration of the widgets
* bit of a fiddle... could cause if the image really is 1x1
* but the preview would not really matter in that case.
*/
nav_dialog->imagewidth = 1;
nav_dialog->imageheight = 1;
nav_dialog->nav_preview_width =
(gimprc.nav_preview_size < 0 || gimprc.nav_preview_size > 256) ?
NAV_PREVIEW_WIDTH : gimprc.nav_preview_size;
nav_dialog->nav_preview_height =
(gimprc.nav_preview_size < 0 || gimprc.nav_preview_size > 256) ?
NAV_PREVIEW_HEIGHT : gimprc.nav_preview_size;
nav_dialog_update_window_marker (nav_dialog);
}
void
nav_popup_click_handler (GtkWidget *widget,
GdkEventButton *event,
gpointer data)
{
GdkEventButton *bevent;
GimpDisplay *gdisp;
GimpDisplayShell *shell;
NavigationDialog *nav_dialog;
gint x, y;
gint x_org, y_org;
gint scr_w, scr_h;
gdisp = GIMP_DISPLAY (data);
shell = GIMP_DISPLAY_SHELL (gdisp->shell);
bevent = (GdkEventButton *) event;
if (! shell->nav_popup)
{
GtkWidget *frame;
shell->nav_popup = nav_dialog = nav_dialog_new (gdisp, NAV_POPUP);
nav_dialog->shell = gtk_window_new (GTK_WINDOW_POPUP);
gtk_widget_set_events (nav_dialog->shell, PREVIEW_MASK);
g_object_weak_ref (G_OBJECT (nav_dialog->shell),
(GWeakNotify) g_free,
nav_dialog);
frame = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
gtk_container_add (GTK_CONTAINER (nav_dialog->shell), frame);
gtk_widget_show (frame);
nav_dialog->preview_frame = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (nav_dialog->preview_frame),
GTK_SHADOW_IN);
gtk_container_add (GTK_CONTAINER (frame), nav_dialog->preview_frame);
gtk_widget_show (nav_dialog->preview_frame);
create_preview_widget (nav_dialog);
gtk_widget_set_extension_events (nav_dialog->preview,
GDK_EXTENSION_EVENTS_ALL);
nav_dialog_disp_area (nav_dialog, nav_dialog->gdisp);
}
else
{
nav_dialog = shell->nav_popup;
gtk_widget_hide (nav_dialog->shell);
nav_dialog_disp_area (nav_dialog, nav_dialog->gdisp);
nav_dialog_update_preview (nav_dialog);
}
/* decide where to put the popup */
gdk_window_get_origin (widget->window, &x_org, &y_org);
scr_w = gdk_screen_width ();
scr_h = gdk_screen_height ();
x = x_org + bevent->x - nav_dialog->dispx -
((nav_dialog->dispwidth - BORDER_PEN_WIDTH + 1) * 0.5) - 2;
y = y_org + bevent->y - nav_dialog->dispy -
((nav_dialog->dispheight - BORDER_PEN_WIDTH + 1)* 0.5) - 2;
/* If the popup doesn't fit into the screen, we have a problem.
* We move the popup onscreen and risk that the pointer is not
* in the square representing the viewable area anymore. Moving
* the pointer will make the image scroll by a large amount,
* but then it works as usual. Probably better than a popup that
* is completely unusable in the lower right of the screen.
*
* Warping the pointer would be another solution ...
*/
x = (x < 0) ? 0 : x;
y = (y < 0) ? 0 : y;
x = (x + nav_dialog->pwidth > scr_w) ? scr_w - nav_dialog->pwidth - 2: x;
y = (y + nav_dialog->pheight > scr_h) ? scr_h - nav_dialog->pheight - 2: y;
gtk_widget_set_uposition (nav_dialog->shell, x, y);
gtk_widget_show (nav_dialog->shell);
gdk_flush();
/* fill in then set up handlers for mouse motion etc */
nav_dialog->motion_offsetx =
(nav_dialog->dispwidth - BORDER_PEN_WIDTH + 1) * 0.5;
nav_dialog->motion_offsety =
(nav_dialog->dispheight - BORDER_PEN_WIDTH + 1) * 0.5;
if (GTK_WIDGET_VISIBLE (nav_dialog->preview))
nav_dialog_grab_pointer (nav_dialog, nav_dialog->preview);
}
/* private functions */
static NavigationDialog *
nav_dialog_new (GimpDisplay *gdisp,
NavWinType ptype)
{
NavigationDialog *nav_dialog;
nav_dialog = g_new0 (NavigationDialog, 1);
nav_dialog->ptype = ptype;
nav_dialog->shell = NULL;
nav_dialog->preview = NULL;
nav_dialog->zoom_label = NULL;
nav_dialog->zoom_adjustment = NULL;
nav_dialog->gdisp = gdisp;
nav_dialog->dispx = -1;
nav_dialog->dispy = -1;
nav_dialog->dispwidth = -1;
nav_dialog->dispheight = -1;
nav_dialog->imagewidth = -1;
nav_dialog->imageheight = -1;
nav_dialog->sq_grabbed = FALSE;
nav_dialog->ratio = 1.0;
nav_dialog->nav_preview_width =
(gimprc.nav_preview_size < 0 || gimprc.nav_preview_size > 256) ?
NAV_PREVIEW_WIDTH : gimprc.nav_preview_size;
nav_dialog->nav_preview_height =
(gimprc.nav_preview_size < 0 || gimprc.nav_preview_size > 256) ?
NAV_PREVIEW_HEIGHT : gimprc.nav_preview_size;
nav_dialog->block_adj_sig = FALSE;
nav_dialog->frozen = FALSE;
nav_dialog->idle_id = 0;
return nav_dialog;
}
static gchar *
nav_dialog_title (GimpDisplay *gdisp)
{
gchar *basename;
gchar *title;
basename = g_path_get_basename (gimp_image_filename (gdisp->gimage));
title = g_strdup_printf (_("Navigation: %s-%d.%d"),
basename,
gimp_image_get_ID (gdisp->gimage),
gdisp->instance);
g_free (basename);
return title;
}
static void
nav_dialog_close_callback (GtkWidget *widget,
gpointer data)
{
NavigationDialog *nav_dialog;
nav_dialog = (NavigationDialog *) data;
gtk_widget_hide (nav_dialog->shell);
}
static void
nav_dialog_disp_area (NavigationDialog *nav_dialog,
GimpDisplay *gdisp)
{
GimpDisplayShell *shell;
GimpImage *gimage;
gint newwidth;
gint newheight;
gdouble xratio;
gdouble yratio; /* Screen res ratio */
gboolean need_update = FALSE;
shell = GIMP_DISPLAY_SHELL (gdisp->shell);
/* Calculate preview size */
gimage = gdisp->gimage;
xratio = SCALEFACTOR_X (gdisp);
yratio = SCALEFACTOR_Y (gdisp);
if (nav_dialog->new_preview)
{
if (GIMP_PREVIEW (nav_dialog->new_preview)->dot_for_dot !=
gdisp->dot_for_dot)
gimp_preview_set_dot_for_dot (GIMP_PREVIEW (nav_dialog->new_preview),
gdisp->dot_for_dot);
gimp_navigation_preview_set_marker
(GIMP_NAVIGATION_PREVIEW (nav_dialog->new_preview),
RINT (shell->offset_x / xratio),
RINT (shell->offset_y / yratio),
RINT (shell->disp_width / xratio),
RINT (shell->disp_height / yratio));
}
nav_dialog->dispx = shell->offset_x * nav_dialog->ratio / xratio + 0.5;
nav_dialog->dispy = shell->offset_y * nav_dialog->ratio/yratio + 0.5;
nav_dialog->dispwidth = (shell->disp_width * nav_dialog->ratio) / xratio + 0.5;
nav_dialog->dispheight = (shell->disp_height * nav_dialog->ratio) / yratio + 0.5;
newwidth = gimage->width;
newheight = gimage->height;
if (! gdisp->dot_for_dot)
{
newwidth =
(newwidth * gdisp->gimage->yresolution) / gdisp->gimage->xresolution;
nav_dialog->dispx =
((shell->offset_x *
gdisp->gimage->yresolution * nav_dialog->ratio) /
(gdisp->gimage->xresolution * xratio)) + 0.5; /*here*/
nav_dialog->dispwidth =
((shell->disp_width *
gdisp->gimage->yresolution * nav_dialog->ratio) /
(gdisp->gimage->xresolution * xratio)) + 0.5; /*here*/
}
if ((nav_dialog->imagewidth > 0 && newwidth != nav_dialog->imagewidth) ||
(nav_dialog->imageheight > 0 && newheight != nav_dialog->imageheight))
{
/* Must change the preview size */
if (nav_dialog->ptype != NAV_POPUP)
{
gtk_window_set_focus (GTK_WINDOW (nav_dialog->shell), NULL);
}
gtk_widget_destroy (nav_dialog->preview);
create_preview_widget (nav_dialog);
need_update = TRUE;
}
nav_dialog->imagewidth = newwidth;
nav_dialog->imageheight = newheight;
/* Normalise */
nav_dialog->dispwidth = MAX (nav_dialog->dispwidth, 2);
nav_dialog->dispheight = MAX (nav_dialog->dispheight, 2);
nav_dialog->dispwidth = MIN (nav_dialog->dispwidth, nav_dialog->pwidth);
nav_dialog->dispheight = MIN (nav_dialog->dispheight, nav_dialog->pheight);
if (need_update)
{
if (nav_dialog->ptype != NAV_POPUP)
{
gtk_window_set_focus (GTK_WINDOW (nav_dialog->shell),
nav_dialog->preview);
nav_dialog_idle_update_preview (nav_dialog);
}
else
{
nav_dialog_update_preview (nav_dialog);
gtk_widget_draw (nav_dialog->preview, NULL);
}
}
}
static void
nav_dialog_draw_sqr (NavigationDialog *nav_dialog,
gboolean undraw,
gint x,
gint y,
gint w,
gint h)
{
if (! nav_dialog->gc)
{
if (! GTK_WIDGET_REALIZED (nav_dialog->shell))
gtk_widget_realize (nav_dialog->shell);
nav_dialog->gc = gdk_gc_new (nav_dialog->shell->window);
gdk_gc_set_function (nav_dialog->gc, GDK_INVERT);
gdk_gc_set_line_attributes (nav_dialog->gc, BORDER_PEN_WIDTH,
GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_ROUND);
}
if (undraw)
{
if (nav_dialog->dispx != 0 ||
nav_dialog->dispy != 0 ||
nav_dialog->pwidth != nav_dialog->dispwidth ||
nav_dialog->pheight != nav_dialog->dispheight)
{
/* first undraw from last co-ords */
gdk_draw_rectangle (nav_dialog->preview->window, nav_dialog->gc,
FALSE,
nav_dialog->dispx,
nav_dialog->dispy,
nav_dialog->dispwidth - BORDER_PEN_WIDTH + 1,
nav_dialog->dispheight - BORDER_PEN_WIDTH + 1);
}
}
if (x != 0 || y != 0 ||
w != nav_dialog->pwidth || h != nav_dialog->pheight)
{
gdk_draw_rectangle (nav_dialog->preview->window, nav_dialog->gc,
FALSE,
x, y,
w - BORDER_PEN_WIDTH + 1,
h - BORDER_PEN_WIDTH + 1);
}
nav_dialog->dispx = x;
nav_dialog->dispy = y;
nav_dialog->dispwidth = w;
nav_dialog->dispheight = h;
}
static void
set_size_data (NavigationDialog *nav_dialog)
{
GimpDisplay *gdisp;
GimpImage *gimage;
gint sel_width;
gint sel_height;
gint pwidth;
gint pheight;
gdisp = nav_dialog->gdisp;
gimage = gdisp->gimage;
sel_width = gimage->width;
sel_height = gimage->height;
if (! gdisp->dot_for_dot)
sel_width =
(sel_width * gdisp->gimage->yresolution) / gdisp->gimage->xresolution;
if (sel_width > sel_height)
{
pwidth = nav_dialog->nav_preview_width;
nav_dialog->ratio = (gdouble) pwidth / (gdouble) sel_width;
}
else
{
pheight = nav_dialog->nav_preview_height;
nav_dialog->ratio = (gdouble) pheight / (gdouble) sel_height;
}
pwidth = sel_width * nav_dialog->ratio + 0.5;
pheight = sel_height * nav_dialog->ratio + 0.5;
nav_dialog->pwidth = pwidth;
nav_dialog->pheight = pheight;
}
static void
create_preview_widget (NavigationDialog *nav_dialog)
{
GtkWidget *preview;
preview = gtk_preview_new (GTK_PREVIEW_COLOR);
gtk_widget_set_events (GTK_WIDGET (preview), PREVIEW_MASK);
GTK_WIDGET_SET_FLAGS (preview, GTK_CAN_FOCUS);
gtk_preview_set_dither (GTK_PREVIEW (preview), GDK_RGB_DITHER_MAX);
gtk_container_add (GTK_CONTAINER (nav_dialog->preview_frame), preview);
gtk_widget_show (preview);
nav_dialog->preview = preview;
set_size_data (nav_dialog);
gtk_preview_size (GTK_PREVIEW (preview),
nav_dialog->pwidth, nav_dialog->pheight);
g_signal_connect (G_OBJECT (preview), "event",
G_CALLBACK (nav_dialog_preview_events),
nav_dialog);
}
static gboolean
nav_dialog_update_preview_idle_func (NavigationDialog *nav_dialog)
{
nav_dialog->idle_id = 0;
/* If the gdisp has gone then don't do anything in this timer */
if (! nav_dialog->gdisp)
return FALSE;
nav_dialog_update_preview (nav_dialog);
nav_dialog_disp_area (nav_dialog, nav_dialog->gdisp);
gtk_widget_queue_draw (nav_dialog->preview);
return FALSE;
}
static void
nav_dialog_idle_update_preview (NavigationDialog *nav_dialog)
{
if (nav_dialog->idle_id)
return;
nav_dialog->idle_id =
g_idle_add_full (G_PRIORITY_LOW,
(GSourceFunc) nav_dialog_update_preview_idle_func,
nav_dialog,
NULL);
}
static void
nav_dialog_update_preview (NavigationDialog *nav_dialog)
{
GimpDisplay *gdisp;
TempBuf *preview_buf;
TempBuf *preview_buf_ptr;
TempBuf *preview_buf_notdot = NULL;
guchar *src, *buf, *dest;
gint x, y;
gint pwidth, pheight;
GimpImage *gimage;
gdouble r, g, b, a, chk;
gint xoff = 0;
gint yoff = 0;
gdisp = nav_dialog->gdisp;
gimage = gdisp->gimage;
gimp_set_busy (gimage->gimp);
/* Min size is 2 */
pwidth = nav_dialog->pwidth;
pheight = nav_dialog->pheight;
/* we need a large normal preview which we will cut down later.
* gimp_image_construct_composite_preview() can't cope with
* dot_for_dot not been set.
*/
if (! gdisp->dot_for_dot)
{
gint sel_width = gimage->width;
gint sel_height = gimage->height;
gdouble tratio;
if (sel_width > sel_height)
tratio = (gdouble) nav_dialog->nav_preview_width / ((gdouble) sel_width);
else
tratio = (gdouble) nav_dialog->nav_preview_height / ((gdouble) sel_height);
pwidth = sel_width * tratio + 0.5;
pheight = sel_height * tratio + 0.5;
}
if (nav_dialog->ratio > 1.0) /* Preview is scaling up! */
{
TempBuf *tmp;
tmp = gimp_viewable_get_new_preview (GIMP_VIEWABLE (gimage),
gimage->width,
gimage->height);
preview_buf = temp_buf_scale (tmp,
pwidth,
pheight);
temp_buf_free (tmp);
}
else
{
preview_buf = gimp_viewable_get_new_preview (GIMP_VIEWABLE (gimage),
MAX (pwidth, 2),
MAX (pheight, 2));
}
/* reset & get new preview
*
* FIXME: should use gimp_preview_scale()
*/
if (! gdisp->dot_for_dot)
{
gint loop1, loop2;
gdouble x_ratio, y_ratio;
guchar *src_data;
guchar *dest_data;
preview_buf_notdot = temp_buf_new (nav_dialog->pwidth,
nav_dialog->pheight,
preview_buf->bytes,
0, 0, NULL);
x_ratio = (gdouble) pwidth / (gdouble) nav_dialog->pwidth;
y_ratio = (gdouble) pheight / (gdouble) nav_dialog->pheight;
src_data = temp_buf_data (preview_buf);
dest_data = temp_buf_data (preview_buf_notdot);
for (loop1 = 0 ; loop1 < nav_dialog->pheight ; loop1++)
for (loop2 = 0 ; loop2 < nav_dialog->pwidth ; loop2++)
{
gint i;
guchar *src_pixel;
guchar *dest_pixel;
src_pixel = src_data +
((gint) (loop2 * x_ratio)) * preview_buf->bytes +
((gint) (loop1 * y_ratio)) * pwidth * preview_buf->bytes;
dest_pixel = dest_data +
(loop2 + loop1 * nav_dialog->pwidth) * preview_buf->bytes;
for (i = 0 ; i < preview_buf->bytes; i++)
*dest_pixel++ = *src_pixel++;
}
pwidth = nav_dialog->pwidth;
pheight = nav_dialog->pheight;
src = temp_buf_data (preview_buf_notdot);
preview_buf_ptr = preview_buf_notdot;
}
else
{
src = temp_buf_data (preview_buf);
preview_buf_ptr = preview_buf;
}
buf = g_new (gchar, preview_buf_ptr->width * 3);
for (y = 0; y < preview_buf_ptr->height ; y++)
{
dest = buf;
switch (preview_buf_ptr->bytes)
{
case 4:
for (x = 0; x < preview_buf_ptr->width; x++)
{
r = ((gdouble) (*(src++))) / 255.0;
g = ((gdouble) (*(src++))) / 255.0;
b = ((gdouble) (*(src++))) / 255.0;
a = ((gdouble) (*(src++))) / 255.0;
chk = ((gdouble) ((( (x^y) & 4 ) << 4) | 128)) / 255.0;
*(dest++) = (guchar) ((chk + (r - chk) * a) * 255.0);
*(dest++) = (guchar) ((chk + (g - chk) * a) * 255.0);
*(dest++) = (guchar) ((chk + (b - chk) * a) * 255.0);
}
break;
case 2:
for (x = 0; x < preview_buf_ptr->width; x++)
{
r = ((gdouble) (*(src++))) / 255.0;
a = ((gdouble) (*(src++))) / 255.0;
chk = ((gdouble) ((( (x^y) & 4 ) << 4) | 128)) / 255.0;
*(dest++) = (guchar) ((chk + (r - chk) * a) * 255.0);
*(dest++) = (guchar) ((chk + (r - chk) * a) * 255.0);
*(dest++) = (guchar) ((chk + (r - chk) * a) * 255.0);
}
break;
default:
g_warning ("nav_dialog_update_preview(): UNKNOWN TempBuf bpp");
}
gtk_preview_draw_row (GTK_PREVIEW (nav_dialog->preview),
buf,
xoff, yoff + y,
preview_buf_ptr->width);
}
g_free (buf);
temp_buf_free (preview_buf);
if (preview_buf_notdot)
temp_buf_free (preview_buf_notdot);
gimp_unset_busy (gimage->gimp);
}
static void
nav_dialog_update_preview_blank (NavigationDialog *nav_dialog)
{
guchar *buf;
guchar *dest;
gint x, y;
gdouble chk;
buf = g_new (gchar, nav_dialog->pwidth * 3);
for (y = 0; y < nav_dialog->pheight ; y++)
{
dest = buf;
for (x = 0; x < nav_dialog->pwidth; x++)
{
chk = ((gdouble) ((( (x^y) & 4 ) << 4) | 128)) / 255.0;
chk *= 128.0;
*(dest++) = (guchar) chk;
*(dest++) = (guchar) chk;
*(dest++) = (guchar) chk;
}
gtk_preview_draw_row (GTK_PREVIEW (nav_dialog->preview),
buf,
0, y, nav_dialog->pwidth);
}
g_free (buf);
}
static void
update_zoom_label (NavigationDialog *nav_dialog)
{
gchar scale_str[MAX_SCALE_BUF];
if (! nav_dialog->zoom_label)
return;
/* Update the zoom scale string */
g_snprintf (scale_str, MAX_SCALE_BUF, "%d:%d",
SCALEDEST (nav_dialog->gdisp),
SCALESRC (nav_dialog->gdisp));
gtk_label_set_text (GTK_LABEL (nav_dialog->zoom_label), scale_str);
}
static void
update_zoom_adjustment (NavigationDialog *nav_dialog)
{
GtkAdjustment *adj;
gdouble f;
gdouble val;
if (! nav_dialog->zoom_adjustment)
return;
adj = GTK_ADJUSTMENT (nav_dialog->zoom_adjustment);
f = (((gdouble) SCALEDEST (nav_dialog->gdisp)) /
((gdouble) SCALESRC (nav_dialog->gdisp)));
if (f < 1.0)
{
val = -1.0 / f;
}
else
{
val = f;
}
if (abs ((gint) adj->value) != (gint) (val - 1) &&
! nav_dialog->block_adj_sig)
{
adj->value = val;
gtk_adjustment_changed (GTK_ADJUSTMENT (nav_dialog->zoom_adjustment));
}
}
static void
nav_dialog_update_real_view (NavigationDialog *nav_dialog,
gint tx,
gint ty)
{
GimpDisplayShell *shell;
gdouble xratio;
gdouble yratio;
gint xoffset;
gint yoffset;
gint xpnt;
gint ypnt;
shell = GIMP_DISPLAY_SHELL (nav_dialog->gdisp->shell);
xratio = SCALEFACTOR_X (nav_dialog->gdisp);
yratio = SCALEFACTOR_Y (nav_dialog->gdisp);
if ((tx + nav_dialog->dispwidth) >= nav_dialog->pwidth)
{
tx = nav_dialog->pwidth; /* Actually should be less...
* but bound check will save us.
*/
}
xpnt = (gint) (((gdouble) (tx) * xratio) / nav_dialog->ratio + 0.5);
if ((ty + nav_dialog->dispheight) >= nav_dialog->pheight)
{
ty = nav_dialog->pheight; /* Same comment as for xpnt above. */
}
ypnt = (gint) (((gdouble) (ty) * yratio) / nav_dialog->ratio + 0.5);
if (! nav_dialog->gdisp->dot_for_dot) /* here */
xpnt = (((gdouble) xpnt *
nav_dialog->gdisp->gimage->xresolution) /
nav_dialog->gdisp->gimage->yresolution) + 0.5;
xoffset = xpnt - shell->offset_x;
yoffset = ypnt - shell->offset_y;
gimp_display_shell_scroll (shell, xoffset, yoffset);
}
static void
nav_dialog_move_to_point (NavigationDialog *nav_dialog,
gint tx,
gint ty)
{
tx = CLAMP (tx, 0, nav_dialog->pwidth);
ty = CLAMP (ty, 0, nav_dialog->pheight);
if ((tx + nav_dialog->dispwidth) >= nav_dialog->pwidth)
{
tx = nav_dialog->pwidth - nav_dialog->dispwidth;
}
if ((ty + nav_dialog->dispheight) >= nav_dialog->pheight)
{
ty = nav_dialog->pheight - nav_dialog->dispheight;
}
if (nav_dialog->dispx == tx && nav_dialog->dispy == ty)
return;
nav_dialog_update_real_view (nav_dialog, tx, ty);
}
static void
nav_dialog_grab_pointer (NavigationDialog *nav_dialog,
GtkWidget *widget)
{
GdkCursor *cursor;
nav_dialog->sq_grabbed = TRUE;
gtk_grab_add (widget);
cursor = gdk_cursor_new (GDK_CROSSHAIR);
gdk_pointer_grab (widget->window, TRUE,
GDK_BUTTON_RELEASE_MASK |
GDK_POINTER_MOTION_HINT_MASK |
GDK_BUTTON_MOTION_MASK |
GDK_EXTENSION_EVENTS_ALL,
widget->window, cursor, 0);
gdk_cursor_unref (cursor);
}
static gboolean
nav_dialog_inside_preview_square (NavigationDialog *nav_dialog,
gint x,
gint y)
{
return (x > nav_dialog->dispx &&
x < nav_dialog->dispx + nav_dialog->dispwidth &&
y > nav_dialog->dispy &&
y < nav_dialog->dispy + nav_dialog->dispheight);
}
static gboolean
nav_dialog_preview_events (GtkWidget *widget,
GdkEvent *event,
gpointer data)
{
NavigationDialog *nav_dialog;
GimpDisplay *gdisp;
GimpDisplayShell *shell;
GdkEventButton *bevent;
GdkEventMotion *mevent;
GdkEventKey *kevent;
GdkModifierType mask;
gint tx = 0;
gint ty = 0;
gint mx;
gint my;
gboolean arrow_key = FALSE;
nav_dialog = (NavigationDialog *) data;
if (! nav_dialog || nav_dialog->frozen)
return FALSE;
gdisp = nav_dialog->gdisp;
shell = GIMP_DISPLAY_SHELL (gdisp->shell);
switch (event->type)
{
case GDK_EXPOSE:
/* call default handler explicitly, then draw the square */
GTK_WIDGET_GET_CLASS (widget)->expose_event (widget,
(GdkEventExpose *) event);
nav_dialog_draw_sqr (nav_dialog, FALSE,
nav_dialog->dispx, nav_dialog->dispy,
nav_dialog->dispwidth, nav_dialog->dispheight);
return TRUE;
case GDK_MAP:
if (nav_dialog->ptype == NAV_POPUP)
{
nav_dialog_update_preview (nav_dialog);
/* First time displayed.... get the pointer! */
nav_dialog_grab_pointer (nav_dialog, nav_dialog->preview);
}
else
{
nav_dialog_idle_update_preview (nav_dialog);
}
break;
case GDK_BUTTON_PRESS:
bevent = (GdkEventButton *) event;
tx = bevent->x;
ty = bevent->y;
/* Must start the move */
switch (bevent->button)
{
case 1:
if (! nav_dialog_inside_preview_square (nav_dialog, tx, ty))
{
/* Direct scroll to the location
* view scrolled to the center or nearest possible point
*/
tx -= nav_dialog->dispwidth / 2;
ty -= nav_dialog->dispheight / 2;
nav_dialog_move_to_point (nav_dialog, tx, ty);
nav_dialog->motion_offsetx = nav_dialog->dispwidth / 2;
nav_dialog->motion_offsety = nav_dialog->dispheight / 2;
}
else
{
nav_dialog->motion_offsetx = tx - nav_dialog->dispx;
nav_dialog->motion_offsety = ty - nav_dialog->dispy;
}
nav_dialog_grab_pointer (nav_dialog, widget);
break;
/* wheelmouse support */
case 4:
if (bevent->state & GDK_SHIFT_MASK)
{
gimp_display_shell_scale (shell, GIMP_ZOOM_IN);
}
else
{
GtkAdjustment *adj =
(bevent->state & GDK_CONTROL_MASK) ?
shell->hsbdata : shell->vsbdata;
gfloat new_value = adj->value - adj->page_increment / 2;
new_value =
CLAMP (new_value, adj->lower, adj->upper - adj->page_size);
gtk_adjustment_set_value (adj, new_value);
}
break;
case 5:
if (bevent->state & GDK_SHIFT_MASK)
{
gimp_display_shell_scale (shell, GIMP_ZOOM_OUT);
}
else
{
GtkAdjustment *adj =
(bevent->state & GDK_CONTROL_MASK) ?
shell->hsbdata : shell->vsbdata;
gfloat new_value = adj->value + adj->page_increment / 2;
new_value = CLAMP (new_value,
adj->lower, adj->upper - adj->page_size);
gtk_adjustment_set_value (adj, new_value);
}
break;
default:
break;
}
break;
case GDK_BUTTON_RELEASE:
bevent = (GdkEventButton *) event;
tx = bevent->x;
ty = bevent->y;
switch (bevent->button)
{
case 1:
nav_dialog->sq_grabbed = FALSE;
gtk_grab_remove (widget);
gdk_pointer_ungrab (0);
if (nav_dialog->ptype == NAV_POPUP)
{
gtk_widget_hide (nav_dialog->shell);
}
gdk_flush ();
break;
default:
break;
}
break;
case GDK_KEY_PRESS:
/* hack for the update preview... needs to be fixed */
kevent = (GdkEventKey *) event;
switch (kevent->keyval)
{
case GDK_space:
gdk_window_raise (gdisp->shell->window);
break;
case GDK_Up:
arrow_key = TRUE;
tx = nav_dialog->dispx;
ty = nav_dialog->dispy - 1;
break;
case GDK_Left:
arrow_key = TRUE;
tx = nav_dialog->dispx - 1;
ty = nav_dialog->dispy;
break;
case GDK_Right:
arrow_key = TRUE;
tx = nav_dialog->dispx + 1;
ty = nav_dialog->dispy;
break;
case GDK_Down:
arrow_key = TRUE;
tx = nav_dialog->dispx;
ty = nav_dialog->dispy + 1;
break;
case GDK_equal:
gimp_display_shell_scale (shell, GIMP_ZOOM_IN);
break;
case GDK_minus:
gimp_display_shell_scale (shell, GIMP_ZOOM_OUT);
break;
default:
break;
}
if (arrow_key)
{
nav_dialog_move_to_point (nav_dialog, tx, ty);
return TRUE;
}
break;
case GDK_MOTION_NOTIFY:
mevent = (GdkEventMotion *) event;
if (! nav_dialog->sq_grabbed)
break;
gdk_window_get_pointer (widget->window, &mx, &my, &mask);
tx = mx;
ty = my;
tx = tx - nav_dialog->motion_offsetx;
ty = ty - nav_dialog->motion_offsety;
nav_dialog_move_to_point (nav_dialog, tx, ty);
break;
default:
break;
}
return FALSE;
}
static void
nav_image_need_update (GimpImage *gimage,
gpointer data)
{
NavigationDialog *nav_dialog;
nav_dialog = (NavigationDialog *) data;
if (! nav_dialog ||
! GTK_WIDGET_VISIBLE (nav_dialog->shell) ||
nav_dialog->frozen)
return;
nav_dialog_idle_update_preview (nav_dialog);
}
static void
navwindow_zoomin (GtkWidget *widget,
gpointer data)
{
NavigationDialog *nav_dialog;
nav_dialog = (NavigationDialog *) data;
if(! nav_dialog || nav_dialog->frozen)
return;
gimp_display_shell_scale (GIMP_DISPLAY_SHELL (nav_dialog->gdisp->shell),
GIMP_ZOOM_IN);
}
static void
navwindow_zoomout (GtkWidget *widget,
gpointer data)
{
NavigationDialog *nav_dialog;
nav_dialog = (NavigationDialog *)data;
if (! nav_dialog || nav_dialog->frozen)
return;
gimp_display_shell_scale (GIMP_DISPLAY_SHELL (nav_dialog->gdisp->shell),
GIMP_ZOOM_OUT);
}
static void
zoom_adj_changed (GtkAdjustment *adj,
gpointer data)
{
NavigationDialog *nav_dialog;
gint scalesrc;
gint scaledest;
nav_dialog = (NavigationDialog *)data;
if (! nav_dialog || nav_dialog->frozen)
return;
if (adj->value < 0.0)
{
scalesrc = abs ((gint) adj->value - 1);
scaledest = 1;
}
else
{
scaledest = abs ((gint) adj->value + 1);
scalesrc = 1;
}
nav_dialog->block_adj_sig = TRUE;
gimp_display_shell_scale (GIMP_DISPLAY_SHELL (nav_dialog->gdisp),
(scaledest * 100) + scalesrc);
nav_dialog->block_adj_sig = FALSE;
}
static GtkWidget *
nav_create_button_area (NavigationDialog *nav_dialog)
{
GtkWidget *hbox;
GtkWidget *vbox;
GtkWidget *button;
GtkWidget *hscale;
gchar scale_str[MAX_SCALE_BUF];
vbox = gtk_vbox_new (FALSE, 0);
hbox = gtk_hbox_new (FALSE, 0);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
button = gimp_pixmap_button_new (zoom_out_xpm, NULL);
GTK_WIDGET_UNSET_FLAGS (button, GTK_RECEIVES_DEFAULT);
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
gtk_widget_show (button);
g_signal_connect (G_OBJECT (button), "clicked",
G_CALLBACK (navwindow_zoomout),
nav_dialog);
/* user zoom ratio */
g_snprintf (scale_str, MAX_SCALE_BUF, "%d:%d",
SCALEDEST (nav_dialog->gdisp),
SCALESRC (nav_dialog->gdisp));
nav_dialog->zoom_label = gtk_label_new (scale_str);
gtk_box_pack_start (GTK_BOX (hbox), nav_dialog->zoom_label, TRUE, TRUE, 0);
gtk_widget_show (nav_dialog->zoom_label);
button = gimp_pixmap_button_new (zoom_in_xpm, NULL);
GTK_WIDGET_UNSET_FLAGS (button, GTK_RECEIVES_DEFAULT);
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
gtk_widget_show (button);
g_signal_connect (G_OBJECT (button), "clicked",
G_CALLBACK (navwindow_zoomin),
nav_dialog);
nav_dialog->zoom_adjustment =
gtk_adjustment_new (0.0, -15.0, 16.0, 1.0, 1.0, 1.0);
g_signal_connect (G_OBJECT (nav_dialog->zoom_adjustment), "value_changed",
G_CALLBACK (zoom_adj_changed),
nav_dialog);
hscale = gtk_hscale_new (GTK_ADJUSTMENT (nav_dialog->zoom_adjustment));
gtk_scale_set_draw_value (GTK_SCALE (hscale), FALSE);
gtk_scale_set_digits (GTK_SCALE (hscale), 0);
gtk_box_pack_start (GTK_BOX (vbox), hscale, TRUE, TRUE, 0);
gtk_widget_show (hscale);
return vbox;
}
static void
nav_dialog_display_changed (GimpContext *context,
GimpDisplay *gdisp,
gpointer data)
{
GimpDisplay *old_gdisp;
GimpImage *gimage;
NavigationDialog *nav_dialog;
gchar *title;
nav_dialog = (NavigationDialog *) data;
old_gdisp = nav_dialog->gdisp;
if (! nav_dialog || gdisp == old_gdisp || ! gdisp)
return;
gtk_widget_set_sensitive (nav_window_auto->shell, TRUE);
nav_dialog->frozen = FALSE;
title = nav_dialog_title (gdisp);
gtk_window_set_title (GTK_WINDOW (nav_dialog->shell), title);
g_free (title);
gimage = gdisp->gimage;
if (gimage && gimp_container_have (context->gimp->images,
GIMP_OBJECT (gimage)))
{
nav_dialog->gdisp = gdisp;
/* Update preview to new display */
nav_dialog_preview_resized (nav_dialog);
if (nav_dialog->new_preview)
gimp_preview_set_viewable (GIMP_PREVIEW (nav_dialog->new_preview),
GIMP_VIEWABLE (gdisp->gimage));
/* Tie into the dirty signal so we can update the preview
* provided we haven't already
*/
if (! g_object_get_data (G_OBJECT (gimage), "nav_handlers_installed"))
{
g_signal_connect (G_OBJECT (gimage), "dirty",
G_CALLBACK (nav_image_need_update),
nav_dialog);
g_signal_connect (G_OBJECT (gimage), "clean",
G_CALLBACK (nav_image_need_update),
nav_dialog);
g_object_set_data (G_OBJECT (gimage),
"nav_handlers_installed",
nav_dialog);
}
}
}
static GimpDisplay *
nav_dialog_get_gdisp (void)
{
GList *list;
for (list = GIMP_LIST (the_gimp->images)->list;
list;
list = g_list_next (list))
{
GimpImage *gimage;
GimpDisplay *gdisp;
gimage = GIMP_IMAGE (list->data);
gdisp = gdisplays_check_valid (NULL, gimage);
if (gdisp)
return gdisp;
}
return NULL;
}