diff --git a/ChangeLog b/ChangeLog index 97ce870c81..447318a2cf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,37 @@ +Thu Aug 12 23:15:53 BST 1999 Andy Thomas + + * app/commands.c + * app/commands.h + * app/disp_callbacks.c + * app/gdisplay.c + * app/gdisplay.h + * app/info_dialog.c + * app/info_dialog.h + * app/info_window.c + * app/info_window.h + * app/menus.c + * app/scale.c + * app/scroll.c + * app/scroll.h + * app/nav_window.c (new) + * app/nav_window.h (new) + * pixmap/dropper.xpm (new) + + New "navigator" image (accessed via /Window Nav..). This gives + an outline of the location of the current view on an image. Eg if your + image window is only showing part of an image then the Window Navigation window will outline the area viewed. You can "drag" the outlined + square around the viewport and the main image will scroll. Additional + a single click outside the square will center the image at that + location. + + Also started to add additional information to a new page inside the + Window information dialog (currently only pixel value is shown). + + Both these features are currently work in progress and unfinished. + In particular the Navigator does not keep in step with changes + to the basic image (however it does keep in step with image size changes and if you modify the size of the image viewing window). It also + does not display the transparent areas of images very nicely. + 1999-08-13 Tor Lillqvist * app/makefile.{cygwin,msc} (gimp_OBJECTS): Add newest files. diff --git a/app/Makefile.am b/app/Makefile.am index 07775cf8b5..7d3e2204c9 100644 --- a/app/Makefile.am +++ b/app/Makefile.am @@ -283,6 +283,8 @@ gimp_SOURCES = \ module_db.h \ move.c \ move.h \ + nav_window.c \ + nav_window.h \ ops_buttons.c \ ops_buttons.h \ palette.c \ diff --git a/app/actions/help-commands.c b/app/actions/help-commands.c index 0f140a5a81..dd2d4fc091 100644 --- a/app/actions/help-commands.c +++ b/app/actions/help-commands.c @@ -39,6 +39,7 @@ #include "gradient.h" #include "image_render.h" #include "info_window.h" +#include "nav_window.h" #include "interface.h" #include "invert.h" #include "lc_dialog.h" @@ -535,6 +536,19 @@ view_window_info_cmd_callback (GtkWidget *widget, info_dialog_popup (gdisp->window_info_dialog); } +void +view_window_nav_cmd_callback (GtkWidget *widget, + gpointer client_data) +{ + GDisplay * gdisp; + return_if_no_display (gdisp); + + if (! gdisp->window_nav_dialog) + gdisp->window_nav_dialog = nav_window_create ((void *) gdisp); + + info_dialog_popup (gdisp->window_nav_dialog); +} + void view_toggle_selection_cmd_callback (GtkWidget *widget, gpointer client_data) diff --git a/app/actions/help-commands.h b/app/actions/help-commands.h index 9088c09850..5b30d36060 100644 --- a/app/actions/help-commands.h +++ b/app/actions/help-commands.h @@ -51,6 +51,7 @@ void view_zoom_1_4_callback (GtkWidget *, gpointer); void view_zoom_1_8_callback (GtkWidget *, gpointer); void view_zoom_1_16_callback (GtkWidget *, gpointer); void view_window_info_cmd_callback (GtkWidget *, gpointer); +void view_window_nav_cmd_callback (GtkWidget *, gpointer); void view_toggle_selection_cmd_callback (GtkWidget *, gpointer); void view_toggle_rulers_cmd_callback (GtkWidget *, gpointer); void view_toggle_guides_cmd_callback (GtkWidget *, gpointer); diff --git a/app/commands.c b/app/commands.c index 0f140a5a81..dd2d4fc091 100644 --- a/app/commands.c +++ b/app/commands.c @@ -39,6 +39,7 @@ #include "gradient.h" #include "image_render.h" #include "info_window.h" +#include "nav_window.h" #include "interface.h" #include "invert.h" #include "lc_dialog.h" @@ -535,6 +536,19 @@ view_window_info_cmd_callback (GtkWidget *widget, info_dialog_popup (gdisp->window_info_dialog); } +void +view_window_nav_cmd_callback (GtkWidget *widget, + gpointer client_data) +{ + GDisplay * gdisp; + return_if_no_display (gdisp); + + if (! gdisp->window_nav_dialog) + gdisp->window_nav_dialog = nav_window_create ((void *) gdisp); + + info_dialog_popup (gdisp->window_nav_dialog); +} + void view_toggle_selection_cmd_callback (GtkWidget *widget, gpointer client_data) diff --git a/app/commands.h b/app/commands.h index 9088c09850..5b30d36060 100644 --- a/app/commands.h +++ b/app/commands.h @@ -51,6 +51,7 @@ void view_zoom_1_4_callback (GtkWidget *, gpointer); void view_zoom_1_8_callback (GtkWidget *, gpointer); void view_zoom_1_16_callback (GtkWidget *, gpointer); void view_window_info_cmd_callback (GtkWidget *, gpointer); +void view_window_nav_cmd_callback (GtkWidget *, gpointer); void view_toggle_selection_cmd_callback (GtkWidget *, gpointer); void view_toggle_rulers_cmd_callback (GtkWidget *, gpointer); void view_toggle_guides_cmd_callback (GtkWidget *, gpointer); diff --git a/app/core/gimpprojection.c b/app/core/gimpprojection.c index 14f6e14bba..20c4524f0b 100644 --- a/app/core/gimpprojection.c +++ b/app/core/gimpprojection.c @@ -35,6 +35,7 @@ #include "interface.h" #include "lc_dialog.h" #include "menus.h" +#include "nav_window.h" #include "plug_in.h" #include "qmask.h" #include "scale.h" @@ -97,6 +98,7 @@ gdisplay_new (GimpImage *gimage, gdisp->dot_for_dot = TRUE; gdisp->gimage = gimage; gdisp->window_info_dialog = NULL; + gdisp->window_nav_dialog = NULL; gdisp->depth = g_visual->depth; gdisp->select = NULL; gdisp->ID = display_num++; @@ -329,6 +331,10 @@ gdisplay_delete (GDisplay *gdisp) if (gdisp->window_info_dialog) info_window_free (gdisp->window_info_dialog); + /* Remove navigation dialog if we have one */ + if(gdisp->window_nav_dialog) + nav_window_free(gdisp->window_nav_dialog); + /* set the active display to NULL if it was this display */ context = gimp_context_get_user (); if (gimp_context_get_display (context) == gdisp) @@ -1010,7 +1016,7 @@ gdisplay_update_cursor (GDisplay *gdisp, int x, int y) } } - gdisplay_untransform_coords(gdisp, x, y, &t_x, &t_y, TRUE, TRUE); + gdisplay_untransform_coords(gdisp, x, y, &t_x, &t_y, FALSE, FALSE); active_drawable = gimp_image_active_drawable (gdisp->gimage); @@ -1022,6 +1028,10 @@ gdisplay_update_cursor (GDisplay *gdisp, int x, int y) t_y >= active_drawable->height) { gtk_label_set (GTK_LABEL (gdisp->cursor_label), ""); + info_window_update_RGB(gdisp->window_info_dialog, + gdisp, + -1, + -1); } else { @@ -1042,6 +1052,10 @@ gdisplay_update_cursor (GDisplay *gdisp, int x, int y) (double) t_y * unit_factor / gdisp->gimage->yresolution); } gtk_label_set (GTK_LABEL (gdisp->cursor_label), buffer); + info_window_update_RGB(gdisp->window_info_dialog, + gdisp, + t_x, + t_y); } } @@ -1051,6 +1065,7 @@ gdisplay_update_cursor (GDisplay *gdisp, int x, int y) if (new_cursor) gdisplay_flush (gdisp); + } diff --git a/app/core/gimpprojection.h b/app/core/gimpprojection.h index d528cc80da..eb63b65d2d 100644 --- a/app/core/gimpprojection.h +++ b/app/core/gimpprojection.h @@ -111,6 +111,7 @@ struct _GDisplay guint progressid; /* id of statusbar message for progress */ InfoDialog *window_info_dialog; /* dialog box for image information */ + InfoDialog *window_nav_dialog; /* dialog box for image navigation */ int color_type; /* is this an RGB or GRAY colormap */ diff --git a/app/dialogs/info-dialog.c b/app/dialogs/info-dialog.c index 696269404a..6b2a750eb5 100644 --- a/app/dialogs/info-dialog.c +++ b/app/dialogs/info-dialog.c @@ -139,15 +139,14 @@ info_dialog_delete_callback (GtkWidget *w, return TRUE; } -/* public functions */ - -InfoDialog * -info_dialog_new (char *title) +static InfoDialog * +info_dialog_new_extended (char *title,gboolean inNotebook) { InfoDialog *idialog; GtkWidget *shell; GtkWidget *vbox; GtkWidget *info_table; + GtkWidget *info_notebook; idialog = g_new (InfoDialog, 1); idialog->field_list = NULL; @@ -167,11 +166,28 @@ info_dialog_new (char *title) gtk_box_pack_start (GTK_BOX (GTK_DIALOG (shell)->vbox), vbox, TRUE, TRUE, 0); info_table = gtk_table_new (2, 0, FALSE); - gtk_box_pack_start (GTK_BOX (vbox), info_table, TRUE, TRUE, 0); + + if(inNotebook) + { + info_notebook = gtk_notebook_new(); + gtk_notebook_append_page(GTK_NOTEBOOK(info_notebook), + info_table, + gtk_label_new (_("General"))); + gtk_box_pack_start (GTK_BOX (vbox), info_notebook, TRUE, TRUE, 0); + } + else + { + info_notebook = NULL; + gtk_box_pack_start (GTK_BOX (vbox), info_table, TRUE, TRUE, 0); + } idialog->shell = shell; idialog->vbox = vbox; idialog->info_table = info_table; + idialog->info_notebook = info_notebook; + + if(inNotebook) + gtk_widget_show (idialog->info_notebook); gtk_widget_show (idialog->info_table); gtk_widget_show (idialog->vbox); @@ -179,6 +195,20 @@ info_dialog_new (char *title) return idialog; } +/* public functions */ + +InfoDialog * +info_dialog_notebook_new (char *title) +{ + return info_dialog_new_extended(title,TRUE); +} + +InfoDialog * +info_dialog_new (char *title) +{ + return info_dialog_new_extended(title,FALSE); +} + void info_dialog_free (InfoDialog *idialog) { diff --git a/app/dialogs/info-dialog.h b/app/dialogs/info-dialog.h index 457918c132..1443406252 100644 --- a/app/dialogs/info-dialog.h +++ b/app/dialogs/info-dialog.h @@ -50,6 +50,7 @@ struct _InfoDialog GtkWidget *shell; GtkWidget *vbox; GtkWidget *info_table; + GtkWidget *info_notebook; GSList *field_list; int nfields; @@ -60,6 +61,7 @@ struct _InfoDialog /* Info Dialog functions */ InfoDialog *info_dialog_new (gchar *title); +InfoDialog *info_dialog_notebook_new (gchar *title); void info_dialog_free (InfoDialog *idialog); void info_dialog_popup (InfoDialog *idialog); diff --git a/app/dialogs/info-window.c b/app/dialogs/info-window.c index 227ab5fad2..67e5b2685d 100644 --- a/app/dialogs/info-window.c +++ b/app/dialogs/info-window.c @@ -15,6 +15,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + #include "appenv.h" #include "actionarea.h" #include "colormaps.h" @@ -23,9 +24,12 @@ #include "gdisplay.h" #include "gximage.h" #include "interface.h" +#include "scroll.h" #include "libgimp/gimpintl.h" #include "libgimp/gimpunit.h" +#include "pixmaps/dropper.xpm" + #define MAX_BUF 256 @@ -40,6 +44,12 @@ struct _InfoWinData char shades_str[MAX_BUF]; char resolution_str[MAX_BUF]; char unit_str[MAX_BUF]; + void *gdisp_ptr; /* I'a not happy 'bout this one */ + GtkWidget *labelBvalue; + GtkWidget *labelGvalue; + GtkWidget *labelRvalue; + GtkWidget *labelAvalue; + gboolean showingPreview; }; /* The different classes of visuals */ @@ -104,6 +114,142 @@ info_window_close_callback (GtkWidget *widget, info_dialog_popdown ((InfoDialog *) client_data); } + +static void +info_window_page_switch (GtkWidget *widget, + GtkNotebookPage *page, + gint page_num) +{ + InfoDialog *info_win; + InfoWinData *iwd; + + info_win = (InfoDialog *)gtk_object_get_user_data(GTK_OBJECT (widget)); + iwd = (InfoWinData *)info_win->user_data; + + /* Only deal with the second page */ + if(page_num != 1) + { + iwd->showingPreview = FALSE; + return; + } + + iwd->showingPreview = TRUE; + +} + +static void +info_window_image_preview_book(InfoDialog *info_win) +{ + GtkWidget *hbox1; + GtkWidget *frame; + GtkWidget *alignment; + GtkWidget *table2; + GtkWidget *labelBvalue; + GtkWidget *labelGvalue; + GtkWidget *labelRvalue; + GtkWidget *labelAvalue; + GtkWidget *labelB; + GtkWidget *labelG; + GtkWidget *labelR; + GtkWidget *labelA; + GtkWidget *pixmapwid; + GdkPixmap *pixmap; + GdkBitmap *mask; + GtkStyle *style; + + InfoWinData *iwd; + + iwd = (InfoWinData *)info_win->user_data; + + hbox1 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox1); + + alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0); + gtk_widget_show (alignment); + + frame = gtk_frame_new(NULL); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (hbox1), alignment, TRUE, TRUE, 0); + + table2 = gtk_table_new (5, 2, TRUE); + gtk_container_border_width (GTK_CONTAINER (table2), 2); + gtk_widget_show (table2); + gtk_container_add (GTK_CONTAINER (frame), table2); + gtk_container_add (GTK_CONTAINER (alignment), frame); + + labelAvalue = gtk_label_new ("N/A"); + gtk_widget_show (labelAvalue); + gtk_table_attach (GTK_TABLE (table2), labelAvalue, 1, 2, 4, 5, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + + labelBvalue = gtk_label_new ("N/A"); + gtk_widget_show (labelBvalue); + gtk_table_attach (GTK_TABLE (table2), labelBvalue, 1, 2, 3, 4, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + + labelGvalue = gtk_label_new ("N/A"); + gtk_widget_show (labelGvalue); + gtk_table_attach (GTK_TABLE (table2), labelGvalue, 1, 2, 2, 3, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + + labelRvalue = gtk_label_new ("N/A"); + gtk_widget_show (labelRvalue); + gtk_table_attach (GTK_TABLE (table2), labelRvalue, 1, 2, 1, 2, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + + labelA = gtk_label_new ("A:"); + gtk_widget_show (labelA); + gtk_table_attach (GTK_TABLE (table2), labelA, 0, 1, 4, 5, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + + labelB = gtk_label_new ("B:"); + gtk_widget_show (labelB); + gtk_table_attach (GTK_TABLE (table2), labelB, 0, 1, 3, 4, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + + labelG = gtk_label_new ("G:"); + gtk_widget_show (labelG); + gtk_table_attach (GTK_TABLE (table2), labelG, 0, 1, 2, 3, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + + labelR = gtk_label_new ("R:"); + gtk_widget_show (labelR); + gtk_table_attach (GTK_TABLE (table2), labelR, 0, 1, 1, 2, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + + gtk_widget_realize(info_win->shell); + style = gtk_widget_get_style (info_win->shell); + + pixmap = gdk_pixmap_create_from_xpm_d (info_win->shell->window, &mask, + &style->bg[GTK_STATE_NORMAL], + dropper_xpm); + pixmapwid = gtk_pixmap_new (pixmap, mask); + + gtk_misc_set_alignment (GTK_MISC (pixmapwid), 0.2, 0.2); + gtk_table_attach (GTK_TABLE (table2), pixmapwid, 0, 2, 0, 1, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (pixmapwid); + + gtk_notebook_append_page(GTK_NOTEBOOK(info_win->info_notebook), + hbox1, + gtk_label_new (_("Extended"))); + + /* Set back to first page */ + gtk_notebook_set_page(GTK_NOTEBOOK(info_win->info_notebook),0); + + gtk_object_set_user_data(GTK_OBJECT (info_win->info_notebook), + (gpointer)info_win); + + gtk_signal_connect (GTK_OBJECT (info_win->info_notebook), "switch_page", + GTK_SIGNAL_FUNC (info_window_page_switch), NULL); + + iwd->labelBvalue = labelBvalue; + iwd->labelGvalue = labelGvalue; + iwd->labelRvalue = labelRvalue; + iwd->labelAvalue = labelAvalue; + +} + /* displays information: * image name * image width, height @@ -136,7 +282,7 @@ info_window_create (void *gdisp_ptr) /* create the info dialog */ title_buf = g_strdup_printf (_("%s: Window Info"), title); - info_win = info_dialog_new (title_buf); + info_win = info_dialog_notebook_new (title_buf); g_free (title_buf); iwd = (InfoWinData *) g_malloc (sizeof (InfoWinData)); @@ -149,6 +295,7 @@ info_window_create (void *gdisp_ptr) iwd->visual_class_str[0] = '\0'; iwd->visual_depth_str[0] = '\0'; iwd->shades_str[0] = '\0'; + iwd->showingPreview = FALSE; /* add the information fields */ info_dialog_add_label (info_win, _("Dimensions (w x h):"), @@ -178,6 +325,9 @@ info_window_create (void *gdisp_ptr) /* update the fields */ info_window_update (info_win, gdisp_ptr); + /* Add extra tabs */ + info_window_image_preview_book(info_win); + /* Create the action area */ action_items[0].user_data = info_win; build_action_area (GTK_DIALOG (info_win->shell), action_items, 1, 0); @@ -185,6 +335,61 @@ info_window_create (void *gdisp_ptr) return info_win; } +void +info_window_update_RGB (InfoDialog *info_win, + void *gdisp_ptr, + gdouble tx, + gdouble ty) +{ + GDisplay *gdisp; + InfoWinData *iwd; + char buff[5]; + guchar *color; + gint has_alpha; + gint sample_type; + + if(!info_win) + return; + + gdisp = (GDisplay *) gdisp_ptr; + iwd = (InfoWinData *) info_win->user_data; + + if(!iwd || iwd->showingPreview == FALSE) + return; + + /* gimage_active_drawable (gdisp->gimage) */ + if (!(color = gimp_image_get_color_at(gdisp->gimage, tx, ty)) + || (tx < 0.0 && ty < 0.0)) + { + g_snprintf(buff,5,"%4s","N/A"); + gtk_label_set_text(GTK_LABEL(iwd->labelBvalue),buff); + gtk_label_set_text(GTK_LABEL(iwd->labelGvalue),buff); + gtk_label_set_text(GTK_LABEL(iwd->labelRvalue),buff); + gtk_label_set_text(GTK_LABEL(iwd->labelAvalue),buff); + + return; + } + + g_snprintf(buff,5,"%4d",(gint)color[BLUE_PIX]); + gtk_label_set_text(GTK_LABEL(iwd->labelBvalue),buff); + g_snprintf(buff,5,"%4d",(gint)color[GREEN_PIX]); + gtk_label_set_text(GTK_LABEL(iwd->labelGvalue),buff); + g_snprintf(buff,5,"%4d",(gint)color[RED_PIX]); + gtk_label_set_text(GTK_LABEL(iwd->labelRvalue),buff); + + sample_type = gimp_image_composite_type (gdisp->gimage); + has_alpha = TYPE_HAS_ALPHA (sample_type); + + if(has_alpha) + g_snprintf(buff,5,"%4d",(gint)color[ALPHA_PIX]); + else + g_snprintf(buff,5,"%4s","N/A"); + + gtk_label_set_text(GTK_LABEL(iwd->labelAvalue),buff); + + g_free(color); +} + void info_window_free (InfoDialog *info_win) { diff --git a/app/dialogs/info-window.h b/app/dialogs/info-window.h index a568c3ecf2..7ca4fae600 100644 --- a/app/dialogs/info-window.h +++ b/app/dialogs/info-window.h @@ -23,6 +23,9 @@ InfoDialog *info_window_create (void *); void info_window_free (InfoDialog *); void info_window_update (InfoDialog *, void *); - +void info_window_update_RGB (InfoDialog *, + void *, + gdouble, + gdouble); #endif /* __INFO_WINDOW_H__ */ diff --git a/app/disp_callbacks.c b/app/disp_callbacks.c index 67dfc7bc10..84fba2ae25 100644 --- a/app/disp_callbacks.c +++ b/app/disp_callbacks.c @@ -26,6 +26,7 @@ #include "general.h" #include "gimpcontext.h" #include "gimprc.h" +#include "info_window.h" #include "interface.h" #include "layer_select.h" #include "move.h" @@ -199,6 +200,10 @@ gdisplay_canvas_events (GtkWidget *canvas, case GDK_LEAVE_NOTIFY: gdisplay_update_cursor (gdisp, 0, 0); gtk_label_set_text (GTK_LABEL (gdisp->cursor_label), ""); + info_window_update_RGB(gdisp->window_info_dialog, + gdisp, + -1, + -1); case GDK_PROXIMITY_OUT: gdisp->proximity = FALSE; diff --git a/app/display/gimpdisplay-callbacks.c b/app/display/gimpdisplay-callbacks.c index 67dfc7bc10..84fba2ae25 100644 --- a/app/display/gimpdisplay-callbacks.c +++ b/app/display/gimpdisplay-callbacks.c @@ -26,6 +26,7 @@ #include "general.h" #include "gimpcontext.h" #include "gimprc.h" +#include "info_window.h" #include "interface.h" #include "layer_select.h" #include "move.h" @@ -199,6 +200,10 @@ gdisplay_canvas_events (GtkWidget *canvas, case GDK_LEAVE_NOTIFY: gdisplay_update_cursor (gdisp, 0, 0); gtk_label_set_text (GTK_LABEL (gdisp->cursor_label), ""); + info_window_update_RGB(gdisp->window_info_dialog, + gdisp, + -1, + -1); case GDK_PROXIMITY_OUT: gdisp->proximity = FALSE; diff --git a/app/display/gimpdisplay-scale.c b/app/display/gimpdisplay-scale.c index 9c73de328d..9fbdd08c47 100644 --- a/app/display/gimpdisplay-scale.c +++ b/app/display/gimpdisplay-scale.c @@ -21,7 +21,7 @@ #include "gdisplay.h" #include "gdisplay_ops.h" #include "gimprc.h" -#include "info_window.h" +#include "nav_window.h" #include "scale.h" #include "tools.h" @@ -257,4 +257,7 @@ setup_scale (GDisplay *gdisp) gtk_widget_draw (GTK_WIDGET (hruler), NULL); gtk_widget_draw (GTK_WIDGET (vruler), NULL); + + if (gdisp->window_nav_dialog) + nav_window_update_window_marker(gdisp->window_nav_dialog); } diff --git a/app/display/gimpdisplay-scroll.c b/app/display/gimpdisplay-scroll.c index 4d3088acee..26322e6343 100644 --- a/app/display/gimpdisplay-scroll.c +++ b/app/display/gimpdisplay-scroll.c @@ -21,6 +21,7 @@ #include "scroll.h" #include "cursorutil.h" #include "tools.h" +#include "nav_window.h" /* This is the delay before dithering begins @@ -28,9 +29,6 @@ */ #define DITHER_DELAY 250 /* milliseconds */ -/* Locally defined functions */ -static int scroll_display (GDisplay *, int, int); - /* STATIC variables */ /* These are the values of the initial pointer grab */ static int startx, starty; @@ -127,10 +125,10 @@ scroll_to_pointer_position (GDisplay *gdisp, } -static int +int scroll_display (GDisplay *gdisp, - int x_offset, - int y_offset) + gint x_offset, + gint y_offset) { int old_x, old_y; int src_x, src_y; @@ -201,6 +199,8 @@ scroll_display (GDisplay *gdisp, if (x_offset || y_offset) gdisplays_flush (); + if (gdisp->window_nav_dialog) + nav_window_update_window_marker(gdisp->window_nav_dialog); /* Make sure graphics expose events are processed before scrolling * again */ diff --git a/app/display/gimpdisplay-scroll.h b/app/display/gimpdisplay-scroll.h index 29876918fb..24b1525162 100644 --- a/app/display/gimpdisplay-scroll.h +++ b/app/display/gimpdisplay-scroll.h @@ -35,4 +35,8 @@ void end_grab_and_scroll (GDisplay *, GdkEventButton *); void grab_and_scroll (GDisplay *, GdkEventMotion *); void scroll_to_pointer_position (GDisplay *, GdkEventMotion *); +/* generic scroll-by-offset function */ +gint scroll_display (GDisplay *, gint, gint); + + #endif /* __SCROLL_H__ */ diff --git a/app/display/gimpdisplay.c b/app/display/gimpdisplay.c index 14f6e14bba..20c4524f0b 100644 --- a/app/display/gimpdisplay.c +++ b/app/display/gimpdisplay.c @@ -35,6 +35,7 @@ #include "interface.h" #include "lc_dialog.h" #include "menus.h" +#include "nav_window.h" #include "plug_in.h" #include "qmask.h" #include "scale.h" @@ -97,6 +98,7 @@ gdisplay_new (GimpImage *gimage, gdisp->dot_for_dot = TRUE; gdisp->gimage = gimage; gdisp->window_info_dialog = NULL; + gdisp->window_nav_dialog = NULL; gdisp->depth = g_visual->depth; gdisp->select = NULL; gdisp->ID = display_num++; @@ -329,6 +331,10 @@ gdisplay_delete (GDisplay *gdisp) if (gdisp->window_info_dialog) info_window_free (gdisp->window_info_dialog); + /* Remove navigation dialog if we have one */ + if(gdisp->window_nav_dialog) + nav_window_free(gdisp->window_nav_dialog); + /* set the active display to NULL if it was this display */ context = gimp_context_get_user (); if (gimp_context_get_display (context) == gdisp) @@ -1010,7 +1016,7 @@ gdisplay_update_cursor (GDisplay *gdisp, int x, int y) } } - gdisplay_untransform_coords(gdisp, x, y, &t_x, &t_y, TRUE, TRUE); + gdisplay_untransform_coords(gdisp, x, y, &t_x, &t_y, FALSE, FALSE); active_drawable = gimp_image_active_drawable (gdisp->gimage); @@ -1022,6 +1028,10 @@ gdisplay_update_cursor (GDisplay *gdisp, int x, int y) t_y >= active_drawable->height) { gtk_label_set (GTK_LABEL (gdisp->cursor_label), ""); + info_window_update_RGB(gdisp->window_info_dialog, + gdisp, + -1, + -1); } else { @@ -1042,6 +1052,10 @@ gdisplay_update_cursor (GDisplay *gdisp, int x, int y) (double) t_y * unit_factor / gdisp->gimage->yresolution); } gtk_label_set (GTK_LABEL (gdisp->cursor_label), buffer); + info_window_update_RGB(gdisp->window_info_dialog, + gdisp, + t_x, + t_y); } } @@ -1051,6 +1065,7 @@ gdisplay_update_cursor (GDisplay *gdisp, int x, int y) if (new_cursor) gdisplay_flush (gdisp); + } diff --git a/app/display/gimpdisplay.h b/app/display/gimpdisplay.h index d528cc80da..eb63b65d2d 100644 --- a/app/display/gimpdisplay.h +++ b/app/display/gimpdisplay.h @@ -111,6 +111,7 @@ struct _GDisplay guint progressid; /* id of statusbar message for progress */ InfoDialog *window_info_dialog; /* dialog box for image information */ + InfoDialog *window_nav_dialog; /* dialog box for image navigation */ int color_type; /* is this an RGB or GRAY colormap */ diff --git a/app/display/gimpdisplayshell-callbacks.c b/app/display/gimpdisplayshell-callbacks.c index 67dfc7bc10..84fba2ae25 100644 --- a/app/display/gimpdisplayshell-callbacks.c +++ b/app/display/gimpdisplayshell-callbacks.c @@ -26,6 +26,7 @@ #include "general.h" #include "gimpcontext.h" #include "gimprc.h" +#include "info_window.h" #include "interface.h" #include "layer_select.h" #include "move.h" @@ -199,6 +200,10 @@ gdisplay_canvas_events (GtkWidget *canvas, case GDK_LEAVE_NOTIFY: gdisplay_update_cursor (gdisp, 0, 0); gtk_label_set_text (GTK_LABEL (gdisp->cursor_label), ""); + info_window_update_RGB(gdisp->window_info_dialog, + gdisp, + -1, + -1); case GDK_PROXIMITY_OUT: gdisp->proximity = FALSE; diff --git a/app/display/gimpdisplayshell-scale.c b/app/display/gimpdisplayshell-scale.c index 9c73de328d..9fbdd08c47 100644 --- a/app/display/gimpdisplayshell-scale.c +++ b/app/display/gimpdisplayshell-scale.c @@ -21,7 +21,7 @@ #include "gdisplay.h" #include "gdisplay_ops.h" #include "gimprc.h" -#include "info_window.h" +#include "nav_window.h" #include "scale.h" #include "tools.h" @@ -257,4 +257,7 @@ setup_scale (GDisplay *gdisp) gtk_widget_draw (GTK_WIDGET (hruler), NULL); gtk_widget_draw (GTK_WIDGET (vruler), NULL); + + if (gdisp->window_nav_dialog) + nav_window_update_window_marker(gdisp->window_nav_dialog); } diff --git a/app/display/gimpdisplayshell-scroll.c b/app/display/gimpdisplayshell-scroll.c index 4d3088acee..26322e6343 100644 --- a/app/display/gimpdisplayshell-scroll.c +++ b/app/display/gimpdisplayshell-scroll.c @@ -21,6 +21,7 @@ #include "scroll.h" #include "cursorutil.h" #include "tools.h" +#include "nav_window.h" /* This is the delay before dithering begins @@ -28,9 +29,6 @@ */ #define DITHER_DELAY 250 /* milliseconds */ -/* Locally defined functions */ -static int scroll_display (GDisplay *, int, int); - /* STATIC variables */ /* These are the values of the initial pointer grab */ static int startx, starty; @@ -127,10 +125,10 @@ scroll_to_pointer_position (GDisplay *gdisp, } -static int +int scroll_display (GDisplay *gdisp, - int x_offset, - int y_offset) + gint x_offset, + gint y_offset) { int old_x, old_y; int src_x, src_y; @@ -201,6 +199,8 @@ scroll_display (GDisplay *gdisp, if (x_offset || y_offset) gdisplays_flush (); + if (gdisp->window_nav_dialog) + nav_window_update_window_marker(gdisp->window_nav_dialog); /* Make sure graphics expose events are processed before scrolling * again */ diff --git a/app/display/gimpdisplayshell-scroll.h b/app/display/gimpdisplayshell-scroll.h index 29876918fb..24b1525162 100644 --- a/app/display/gimpdisplayshell-scroll.h +++ b/app/display/gimpdisplayshell-scroll.h @@ -35,4 +35,8 @@ void end_grab_and_scroll (GDisplay *, GdkEventButton *); void grab_and_scroll (GDisplay *, GdkEventMotion *); void scroll_to_pointer_position (GDisplay *, GdkEventMotion *); +/* generic scroll-by-offset function */ +gint scroll_display (GDisplay *, gint, gint); + + #endif /* __SCROLL_H__ */ diff --git a/app/display/gimpnavigationeditor.c b/app/display/gimpnavigationeditor.c new file mode 100644 index 0000000000..67d3df2e02 --- /dev/null +++ b/app/display/gimpnavigationeditor.c @@ -0,0 +1,799 @@ +/* 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 "appenv.h" +#include "actionarea.h" +#include "colormaps.h" +#include "info_dialog.h" +#include "info_window.h" +#include "gdisplay.h" +#include "gximage.h" +#include "interface.h" +#include "scroll.h" + +#include "libgimp/gimpintl.h" +#include "libgimp/gimpunit.h" + + +#define MAX_BUF 256 + +#define PREVIEW_MASK GDK_EXPOSURE_MASK | \ + GDK_MOTION_NOTIFY | \ + GDK_POINTER_MOTION_MASK | \ + GDK_BUTTON_PRESS_MASK | \ + GDK_BUTTON_RELEASE_MASK | \ + GDK_BUTTON_MOTION_MASK | \ + GDK_KEY_PRESS_MASK | \ + GDK_KEY_RELEASE_MASK + +/* Navigation preview sizes */ +#define NAV_PREVIEW_WIDTH 112 +#define NAV_PREVIEW_HEIGHT 112 +#define BORDER_PEN_WIDTH 3 + +typedef struct _NavWinData NavWinData; +struct _NavWinData +{ + gboolean showingPreview; + GtkWidget *preview; + void *gdisp_ptr; /* I'a not happy 'bout this one */ + GtkWidget *previewBox; + GtkWidget *previewAlign; + gdouble ratio; + 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 left corner of display area */ + gint sig_hand_id; + 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 */ + gboolean block_window_marker; /* Block redraws of window marker */ + gint nav_preview_width; + gint nav_preview_height; +}; + + +static gint +nav_window_preview_events (GtkWidget *, + GdkEvent *, + gpointer *); +static gint +nav_window_expose_events (GtkWidget *, + GdkEvent *, + gpointer *); + +#if 0 +static gint +nav_window_preview_resized (GtkWidget *, + GtkAllocation *, + gpointer *); + +#endif /* 0 */ + +static void +nav_window_update_preview (NavWinData *); + +static void +destroy_preview_widget (NavWinData *); + +static void +create_preview_widget (NavWinData *); + +void +nav_window_update_window_marker(InfoDialog *); + +static void +nav_window_draw_sqr(NavWinData *, + gboolean, + gint , + gint , + gint , + gint ); + +static void +set_size_data(NavWinData *); + +static void +nav_window_close_callback (GtkWidget *widget, + gpointer client_data) +{ + InfoDialog *info_win; + NavWinData *iwd; + + info_win = (InfoDialog *)client_data; + iwd = (NavWinData *)info_win->user_data; + + /* iwd->showingPreview = FALSE; ALT. Needs to be sorted out */ + info_dialog_popdown ((InfoDialog *) client_data); +} + +static void +nav_window_disp_area(NavWinData *iwd,GDisplay *gdisp) +{ + GimpImage *gimage; + gint newwidth; + gint newheight; + gdouble ratio; /* Screen res ratio */ + gboolean need_update = FALSE; + + /* Calculate preview size */ + gimage = gdisp->gimage; + + ratio = ((gdouble)SCALEDEST(gdisp))/((gdouble)SCALESRC(gdisp)); + + iwd->dispx = gdisp->offset_x*iwd->ratio/ratio; + iwd->dispy = gdisp->offset_y*iwd->ratio/ratio; + iwd->dispwidth = (gdisp->disp_width*iwd->ratio)/ratio; + iwd->dispheight = (gdisp->disp_height*iwd->ratio)/ratio; + + newwidth = gimage->width; + newheight = gimage->height; + + if((iwd->imagewidth > 0 && newwidth != iwd->imagewidth) || + (iwd->imageheight > 0 && newheight != iwd->imageheight)) + { + /* Must change the preview size */ + destroy_preview_widget(iwd); + create_preview_widget(iwd); + need_update = TRUE; + } + + iwd->imagewidth = newwidth; + iwd->imageheight = newheight; + + /* Normalise */ + iwd->dispwidth = MIN(iwd->dispwidth, iwd->pwidth-BORDER_PEN_WIDTH); + iwd->dispheight = MIN(iwd->dispheight, iwd->pheight-BORDER_PEN_WIDTH); + + if(need_update == TRUE) + { + gtk_widget_hide(iwd->previewAlign); + nav_window_update_preview(iwd); + gtk_widget_show(iwd->preview); + gtk_widget_draw(iwd->preview, NULL); + gtk_widget_show(iwd->previewAlign); + nav_window_draw_sqr(iwd,FALSE, + iwd->dispx,iwd->dispy, + iwd->dispwidth,iwd->dispheight); + } +} + +static void +nav_window_draw_sqr(NavWinData *iwd, + gboolean undraw, + gint x, + gint y, + gint w, + gint h) +{ + GDisplay *gdisp; + + gdisp = (GDisplay *) iwd->gdisp_ptr; + + gdk_gc_set_function (iwd->gc, GDK_INVERT); + + + if(undraw) + { + /* first undraw from last co-ords */ + gdk_draw_rectangle (iwd->preview->window, iwd->gc, FALSE, + iwd->dispx,iwd->dispy, + iwd->dispwidth, + iwd->dispheight); + } + +/* gdk_draw_rectangle (iwd->preview->window, iwd->gc, FALSE, */ +/* 10,20, */ +/* 40,50); */ + + gdk_draw_rectangle (iwd->preview->window, iwd->gc, FALSE, + x,y, + w, + h); + + iwd->dispx = x; + iwd->dispy = y; + iwd->dispwidth = w; + iwd->dispheight = h; +} + +static void +destroy_preview_widget(NavWinData *iwd) +{ + if(!iwd->preview) + return; + + gtk_widget_hide(iwd->previewBox); + gtk_widget_destroy(iwd->previewBox); + iwd->previewBox = NULL; + iwd->preview = NULL; +} + +static void +set_size_data(NavWinData *iwd) +{ + gint sel_width, sel_height; + gint pwidth, pheight; + GDisplay *gdisp; + GimpImage *gimage; + + gdisp = (GDisplay *)(iwd->gdisp_ptr); + gimage = gdisp->gimage; + + sel_width = gimage->width; + sel_height = gimage->height; + + if (sel_width > sel_height) { + pwidth = MIN(sel_width, iwd->nav_preview_width); + pheight = sel_height * pwidth / sel_width; + iwd->ratio = (gdouble)pwidth / ((gdouble)sel_width); + } else { + pheight = MIN(sel_height, iwd->nav_preview_height); + pwidth = sel_width * pheight / sel_height; + iwd->ratio = (gdouble)pheight / ((gdouble)sel_height); + } + + iwd->pwidth = pwidth; + iwd->pheight = pheight; +} + +static void +create_preview_widget(NavWinData *iwd) +{ + GtkWidget *hbox; + GtkWidget *image; + GtkWidget *frame; + gdouble ratio; + GDisplay *gdisp; + + gdisp = (GDisplay *)(iwd->gdisp_ptr); + + ratio = ((gdouble)SCALEDEST(gdisp))/((gdouble)SCALESRC(gdisp)); + + hbox = gtk_hbox_new(FALSE,0); + iwd->previewBox = hbox; + gtk_widget_show(hbox); + gtk_container_add(GTK_CONTAINER (iwd->previewAlign),hbox); + + image = gtk_preview_new (GTK_PREVIEW_COLOR); + iwd->preview = image; + gtk_widget_show (image); + + gtk_preview_set_dither (GTK_PREVIEW (image), GDK_RGB_DITHER_MAX); + gtk_widget_set_events( GTK_WIDGET(image), PREVIEW_MASK ); + + set_size_data(iwd); + + gtk_preview_size (GTK_PREVIEW (iwd->preview), + iwd->pwidth, + iwd->pheight); + + gtk_widget_set_usize (iwd->preview, + iwd->pwidth, + iwd->pheight); + + frame = gtk_frame_new(NULL); + gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN); + gtk_container_add(GTK_CONTAINER (iwd->previewBox),frame); + gtk_container_add (GTK_CONTAINER (frame), iwd->preview); + gtk_widget_show(frame); + + iwd->sig_hand_id = gtk_signal_connect_after (GTK_OBJECT (image), "expose_event", + (GtkSignalFunc) nav_window_expose_events, + iwd); + + gtk_signal_connect (GTK_OBJECT (image), "event", + (GtkSignalFunc) nav_window_preview_events, + iwd); + +/* gtk_signal_connect (GTK_OBJECT (image), "size_allocate", */ +/* (GtkSignalFunc) nav_window_preview_resized, */ +/* iwd); */ + + gtk_widget_grab_focus(image); + +} + +#if 0 +static void +info_window_page_switch (GtkWidget *widget, + GtkNotebookPage *page, + gint page_num) +{ + InfoDialog *info_win; + InfoWinData *iwd; + + info_win = (InfoDialog *)gtk_object_get_user_data(GTK_OBJECT (widget)); + iwd = (InfoWinData *)info_win->user_data; + + /* Only deal with the second page */ + if(page_num != 1) + { + iwd->showingPreview = FALSE; + return; + } + + iwd->showingPreview = TRUE; + +} +#endif /* 0 */ + +static void +update_real_view(NavWinData *iwd,gint tx,gint ty) +{ + GDisplay *gdisp; + gdouble ratio; + gint xoffset; + gint yoffset; + + gdisp = (GDisplay *) iwd->gdisp_ptr; + ratio = ((gdouble)SCALEDEST(gdisp))/((gdouble)SCALESRC(gdisp)); + + xoffset = tx - iwd->dispx; + yoffset = ty - iwd->dispy; + + xoffset = (gint)(((gdouble)xoffset*ratio)/iwd->ratio); + yoffset = (gint)(((gdouble)yoffset*ratio)/iwd->ratio); + + iwd->block_window_marker = TRUE; + scroll_display(iwd->gdisp_ptr,xoffset,yoffset); + iwd->block_window_marker = FALSE; +} + +static void +nav_window_update_preview(NavWinData *iwd) +{ + GDisplay *gdisp; + TempBuf * preview_buf; + gchar *src, *buf; + gint x,y,has_alpha; + gint pwidth, pheight; + GimpImage *gimage; + gdisp = (GDisplay *) iwd->gdisp_ptr; + + /* Calculate preview size */ + gimage = ((GDisplay *)(iwd->gdisp_ptr))->gimage; + + /* Min size is 2 */ + pwidth = iwd->pwidth; + pheight = iwd->pheight; + + preview_buf = gimp_image_construct_composite_preview (gimage, + MAX (pwidth, 2), + MAX (pheight, 2)); + + buf = g_new (gchar, iwd->nav_preview_width * 3); + src = (gchar *) temp_buf_data (preview_buf); + has_alpha = (preview_buf->bytes == 2 || preview_buf->bytes == 4); + for (y = 0; y height ; y++) + { + if (preview_buf->bytes == (1+has_alpha)) + for (x = 0; x < preview_buf->width; x++) + { + buf[x*3+0] = src[x]; + buf[x*3+1] = src[x]; + buf[x*3+2] = src[x]; + } + else + for (x = 0; x < preview_buf->width; x++) + { + gint stride = 3 + has_alpha; + buf[x*3+0] = src[x*stride+0]; + buf[x*3+1] = src[x*stride+1]; + buf[x*3+2] = src[x*stride+2]; + } + gtk_preview_draw_row (GTK_PREVIEW (iwd->preview), + (guchar *)buf, 0, y, preview_buf->width); + src += preview_buf->width * preview_buf->bytes; + } + + g_free (buf); + temp_buf_free (preview_buf); + + nav_window_disp_area(iwd,gdisp); +} + +static gint +inside_preview_square(NavWinData *iwd, gint x, gint y) +{ + if(x > iwd->dispx && + x < (iwd->dispx + iwd->dispwidth) && + y > iwd->dispy && + y < iwd->dispy + iwd->dispheight) + return TRUE; + + return FALSE; +} + +#if 0 +static gint +nav_window_preview_resized (GtkWidget *widget, + GtkAllocation *alloc, + gpointer *data) +{ + NavWinData *iwd; + + iwd = (NavWinData *)data; + + if(!iwd || !iwd->preview) + return FALSE; + + printf("Now at [x,y] = [%d,%d] [w,h] = [%d,%d]\n", + alloc->x,alloc->y, + alloc->width,alloc->height); + + if(iwd->nav_preview_width == alloc->width && + iwd->nav_preview_height == alloc->height) + return FALSE; + + iwd->nav_preview_width = alloc->width; + iwd->nav_preview_height = alloc->height; + set_size_data(iwd); + gtk_preview_size(GTK_PREVIEW(iwd->preview),alloc->width,alloc->height); + nav_window_update_preview(iwd); + nav_window_draw_sqr(iwd,FALSE, + iwd->dispx,iwd->dispy, + iwd->dispwidth,iwd->dispheight); + +#if 0 + destroy_preview_widget(iwd); + create_preview_widget(iwd); + nav_window_update_preview(iwd); + + + nav_window_update_preview(iwd); + gtk_widget_show(iwd->preview); + gtk_widget_draw(iwd->preview, NULL); + gtk_widget_show(iwd->previewAlign); + nav_window_draw_sqr(iwd,FALSE, + iwd->dispx,iwd->dispy, + iwd->dispwidth,iwd->dispheight); + +#endif /* 0 */ + return FALSE; +} + +#endif /* 0 */ + +static gint +nav_window_preview_events (GtkWidget *widget, + GdkEvent *event, + gpointer *data) +{ + NavWinData *iwd; + GDisplay *gdisp; + GdkEventButton *bevent; + GdkEventMotion *mevent; + gint tx,ty; + + iwd = (NavWinData *)data; + + if(!iwd) + return FALSE; + + gdisp = (GDisplay *) iwd->gdisp_ptr; + + switch (event->type) + { + case GDK_EXPOSE: + break; + + case GDK_MAP: + nav_window_update_preview(iwd); + break; + + case GDK_BUTTON_PRESS: + bevent = (GdkEventButton *) event; + tx = bevent->x; + ty = bevent->y; + + /* Must start the move */ + + switch (bevent->button) + { + case 1: + if(inside_preview_square(iwd,tx,ty)) + { + iwd->motion_offsetx = tx - iwd->dispx; + iwd->motion_offsety = ty - iwd->dispy; + iwd->sq_grabbed = TRUE; + gtk_grab_add(widget); + } + else + { + /* Direct scroll to the location */ + /* view scrolled to the center or nearest possible point */ + + tx -= iwd->dispwidth/2; + ty -= iwd->dispheight/2; + + if(tx < 0) + tx = 0; + + if((tx + iwd->dispwidth) > iwd->pwidth) + tx = iwd->pwidth - iwd->dispwidth; + + if(ty < 0) + ty = 0; + + if((ty + iwd->dispheight) > iwd->pheight) + ty = iwd->pheight - iwd->dispheight; + + update_real_view(iwd,tx,ty); + + nav_window_draw_sqr(iwd, + TRUE, + tx,ty, + iwd->dispwidth,iwd->dispheight); + } + break; + default: + } + break; + + case GDK_BUTTON_RELEASE: + bevent = (GdkEventButton *) event; + tx = bevent->x; + ty = bevent->y; + + switch (bevent->button) + { + case 1: + iwd->sq_grabbed = FALSE; + gtk_grab_remove(widget); + break; + default: + } + break; + + case GDK_MOTION_NOTIFY: + mevent = (GdkEventMotion *) event; + + if(!iwd->sq_grabbed) + break; + + tx = mevent->x; + ty = mevent->y; + + if(tx < 0) + { + tx = 0; + } + + if(tx > iwd->pwidth) + { + tx = iwd->pwidth; + } + + if(ty < 0) + { + ty = 0; + } + + if(ty > iwd->pheight) + { + ty = iwd->pwidth; + } + + tx = tx - iwd->motion_offsetx; + ty = ty - iwd->motion_offsety; + + if(tx < 0 || (tx + iwd->dispwidth) >= iwd->pwidth) + { + iwd->motion_offsetx = mevent->x - iwd->dispx; + tx = iwd->dispx; + } + + if(ty < 0 || (ty + iwd->dispheight) >= iwd->pheight) + { + iwd->motion_offsety = mevent->y - iwd->dispy; + ty = iwd->dispy; + } + + /* Update the real display */ + update_real_view(iwd,tx,ty); + + nav_window_draw_sqr(iwd, + TRUE, + tx,ty, + iwd->dispwidth,iwd->dispheight); + + break; + + default: + break; + } + + return FALSE; +} + +static gint +nav_window_expose_events (GtkWidget *widget, + GdkEvent *event, + gpointer *data) +{ + NavWinData *iwd; + GDisplay *gdisp; + + iwd = (NavWinData *)data; + + if(!iwd) + return FALSE; + + gdisp = (GDisplay *) iwd->gdisp_ptr; + + switch (event->type) + { + case GDK_EXPOSE: + gtk_signal_handler_block(GTK_OBJECT(widget),iwd->sig_hand_id); + gtk_widget_draw(iwd->preview, NULL); + gtk_signal_handler_unblock(GTK_OBJECT(widget),iwd->sig_hand_id ); + + nav_window_draw_sqr(iwd,FALSE, + iwd->dispx,iwd->dispy, + iwd->dispwidth,iwd->dispheight); + + break; + case GDK_KEY_PRESS: + /* hack for the update preview... needs to be fixed */ + nav_window_update_preview(iwd); + gtk_widget_draw(iwd->preview, NULL); + break; + default: + break; + } + + return FALSE; +} + + +static GtkWidget * +info_window_image_preview_new(InfoDialog *info_win) +{ + GtkWidget *hbox1; + GtkWidget *alignment; + + NavWinData *iwd; + + iwd = (NavWinData *)info_win->user_data; + + hbox1 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox1); + + gtk_widget_realize(info_win->shell); + + /* need gc to draw the preview sqr with */ + iwd->gc = gdk_gc_new(info_win->shell->window); + gdk_gc_set_function (iwd->gc, GDK_INVERT); + gdk_gc_set_line_attributes (iwd->gc, BORDER_PEN_WIDTH, GDK_LINE_SOLID, + GDK_CAP_BUTT, GDK_JOIN_ROUND); + + alignment = gtk_alignment_new(0.5,0.5,0.0,0.0); + iwd->previewAlign = alignment; + gtk_widget_show (alignment); + + /* Create the preview in which to draw the thumbnail image */ + + create_preview_widget(iwd); + + gtk_box_pack_start (GTK_BOX (hbox1), alignment, TRUE, TRUE, 0); + + return hbox1; +} + +static ActionAreaItem action_items[] = +{ + { N_("Close"), nav_window_close_callback, NULL, NULL }, +}; + +InfoDialog * +nav_window_create (void *gdisp_ptr) +{ + InfoDialog *info_win; + GDisplay *gdisp; + NavWinData *iwd; + GtkWidget *container; + char *title; + char *title_buf; + int type; + + gdisp = (GDisplay *) gdisp_ptr; + + title = g_basename (gimage_filename (gdisp->gimage)); + type = gimage_base_type (gdisp->gimage); + + /* create the info dialog */ + title_buf = g_strdup_printf (_("%s: Window Navigation"), title); + info_win = info_dialog_new (title_buf); + g_free (title_buf); +/* gtk_window_set_policy (GTK_WINDOW (info_win->shell), */ +/* FALSE,FALSE,FALSE); */ + + iwd = (NavWinData *) g_malloc (sizeof (NavWinData)); + info_win->user_data = iwd; + iwd->showingPreview = TRUE; + iwd->preview = NULL; + iwd->gdisp_ptr = gdisp_ptr; + iwd->dispx = -1; + iwd->dispy = -1; + iwd->dispwidth = -1; + iwd->dispheight = -1; + iwd->imagewidth = -1; + iwd->imageheight = -1; + iwd->sq_grabbed = FALSE; + iwd->ratio = 1.0; + iwd->block_window_marker = FALSE; + iwd->nav_preview_width = NAV_PREVIEW_WIDTH; + iwd->nav_preview_height = NAV_PREVIEW_HEIGHT; + + /* Add preview */ + container = info_window_image_preview_new(info_win); + gtk_table_attach_defaults (GTK_TABLE (info_win->info_table), container, + 0, 2, 0, 1); + /* Create the action area */ + action_items[0].user_data = info_win; + build_action_area (GTK_DIALOG (info_win->shell), action_items, 1, 0); + + return info_win; +} + +void +nav_window_update_window_marker(InfoDialog *info_win) +{ + NavWinData *iwd; + + if(!info_win) + return; + + iwd = (NavWinData *)info_win->user_data; + + if(!iwd || + iwd->showingPreview == FALSE || + iwd->block_window_marker == TRUE) + return; + + /* Undraw old size */ + nav_window_draw_sqr(iwd, + FALSE, + iwd->dispx, + iwd->dispy, + iwd->dispwidth,iwd->dispheight); + + /* Update to new size */ + nav_window_disp_area(iwd,iwd->gdisp_ptr); + + /* and redraw */ + nav_window_draw_sqr(iwd, + FALSE, + iwd->dispx, + iwd->dispy, + iwd->dispwidth,iwd->dispheight); +} + +void +nav_window_free (InfoDialog *info_win) +{ + g_free (info_win->user_data); + info_dialog_free (info_win); +} diff --git a/app/display/gimpnavigationview.c b/app/display/gimpnavigationview.c new file mode 100644 index 0000000000..67d3df2e02 --- /dev/null +++ b/app/display/gimpnavigationview.c @@ -0,0 +1,799 @@ +/* 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 "appenv.h" +#include "actionarea.h" +#include "colormaps.h" +#include "info_dialog.h" +#include "info_window.h" +#include "gdisplay.h" +#include "gximage.h" +#include "interface.h" +#include "scroll.h" + +#include "libgimp/gimpintl.h" +#include "libgimp/gimpunit.h" + + +#define MAX_BUF 256 + +#define PREVIEW_MASK GDK_EXPOSURE_MASK | \ + GDK_MOTION_NOTIFY | \ + GDK_POINTER_MOTION_MASK | \ + GDK_BUTTON_PRESS_MASK | \ + GDK_BUTTON_RELEASE_MASK | \ + GDK_BUTTON_MOTION_MASK | \ + GDK_KEY_PRESS_MASK | \ + GDK_KEY_RELEASE_MASK + +/* Navigation preview sizes */ +#define NAV_PREVIEW_WIDTH 112 +#define NAV_PREVIEW_HEIGHT 112 +#define BORDER_PEN_WIDTH 3 + +typedef struct _NavWinData NavWinData; +struct _NavWinData +{ + gboolean showingPreview; + GtkWidget *preview; + void *gdisp_ptr; /* I'a not happy 'bout this one */ + GtkWidget *previewBox; + GtkWidget *previewAlign; + gdouble ratio; + 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 left corner of display area */ + gint sig_hand_id; + 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 */ + gboolean block_window_marker; /* Block redraws of window marker */ + gint nav_preview_width; + gint nav_preview_height; +}; + + +static gint +nav_window_preview_events (GtkWidget *, + GdkEvent *, + gpointer *); +static gint +nav_window_expose_events (GtkWidget *, + GdkEvent *, + gpointer *); + +#if 0 +static gint +nav_window_preview_resized (GtkWidget *, + GtkAllocation *, + gpointer *); + +#endif /* 0 */ + +static void +nav_window_update_preview (NavWinData *); + +static void +destroy_preview_widget (NavWinData *); + +static void +create_preview_widget (NavWinData *); + +void +nav_window_update_window_marker(InfoDialog *); + +static void +nav_window_draw_sqr(NavWinData *, + gboolean, + gint , + gint , + gint , + gint ); + +static void +set_size_data(NavWinData *); + +static void +nav_window_close_callback (GtkWidget *widget, + gpointer client_data) +{ + InfoDialog *info_win; + NavWinData *iwd; + + info_win = (InfoDialog *)client_data; + iwd = (NavWinData *)info_win->user_data; + + /* iwd->showingPreview = FALSE; ALT. Needs to be sorted out */ + info_dialog_popdown ((InfoDialog *) client_data); +} + +static void +nav_window_disp_area(NavWinData *iwd,GDisplay *gdisp) +{ + GimpImage *gimage; + gint newwidth; + gint newheight; + gdouble ratio; /* Screen res ratio */ + gboolean need_update = FALSE; + + /* Calculate preview size */ + gimage = gdisp->gimage; + + ratio = ((gdouble)SCALEDEST(gdisp))/((gdouble)SCALESRC(gdisp)); + + iwd->dispx = gdisp->offset_x*iwd->ratio/ratio; + iwd->dispy = gdisp->offset_y*iwd->ratio/ratio; + iwd->dispwidth = (gdisp->disp_width*iwd->ratio)/ratio; + iwd->dispheight = (gdisp->disp_height*iwd->ratio)/ratio; + + newwidth = gimage->width; + newheight = gimage->height; + + if((iwd->imagewidth > 0 && newwidth != iwd->imagewidth) || + (iwd->imageheight > 0 && newheight != iwd->imageheight)) + { + /* Must change the preview size */ + destroy_preview_widget(iwd); + create_preview_widget(iwd); + need_update = TRUE; + } + + iwd->imagewidth = newwidth; + iwd->imageheight = newheight; + + /* Normalise */ + iwd->dispwidth = MIN(iwd->dispwidth, iwd->pwidth-BORDER_PEN_WIDTH); + iwd->dispheight = MIN(iwd->dispheight, iwd->pheight-BORDER_PEN_WIDTH); + + if(need_update == TRUE) + { + gtk_widget_hide(iwd->previewAlign); + nav_window_update_preview(iwd); + gtk_widget_show(iwd->preview); + gtk_widget_draw(iwd->preview, NULL); + gtk_widget_show(iwd->previewAlign); + nav_window_draw_sqr(iwd,FALSE, + iwd->dispx,iwd->dispy, + iwd->dispwidth,iwd->dispheight); + } +} + +static void +nav_window_draw_sqr(NavWinData *iwd, + gboolean undraw, + gint x, + gint y, + gint w, + gint h) +{ + GDisplay *gdisp; + + gdisp = (GDisplay *) iwd->gdisp_ptr; + + gdk_gc_set_function (iwd->gc, GDK_INVERT); + + + if(undraw) + { + /* first undraw from last co-ords */ + gdk_draw_rectangle (iwd->preview->window, iwd->gc, FALSE, + iwd->dispx,iwd->dispy, + iwd->dispwidth, + iwd->dispheight); + } + +/* gdk_draw_rectangle (iwd->preview->window, iwd->gc, FALSE, */ +/* 10,20, */ +/* 40,50); */ + + gdk_draw_rectangle (iwd->preview->window, iwd->gc, FALSE, + x,y, + w, + h); + + iwd->dispx = x; + iwd->dispy = y; + iwd->dispwidth = w; + iwd->dispheight = h; +} + +static void +destroy_preview_widget(NavWinData *iwd) +{ + if(!iwd->preview) + return; + + gtk_widget_hide(iwd->previewBox); + gtk_widget_destroy(iwd->previewBox); + iwd->previewBox = NULL; + iwd->preview = NULL; +} + +static void +set_size_data(NavWinData *iwd) +{ + gint sel_width, sel_height; + gint pwidth, pheight; + GDisplay *gdisp; + GimpImage *gimage; + + gdisp = (GDisplay *)(iwd->gdisp_ptr); + gimage = gdisp->gimage; + + sel_width = gimage->width; + sel_height = gimage->height; + + if (sel_width > sel_height) { + pwidth = MIN(sel_width, iwd->nav_preview_width); + pheight = sel_height * pwidth / sel_width; + iwd->ratio = (gdouble)pwidth / ((gdouble)sel_width); + } else { + pheight = MIN(sel_height, iwd->nav_preview_height); + pwidth = sel_width * pheight / sel_height; + iwd->ratio = (gdouble)pheight / ((gdouble)sel_height); + } + + iwd->pwidth = pwidth; + iwd->pheight = pheight; +} + +static void +create_preview_widget(NavWinData *iwd) +{ + GtkWidget *hbox; + GtkWidget *image; + GtkWidget *frame; + gdouble ratio; + GDisplay *gdisp; + + gdisp = (GDisplay *)(iwd->gdisp_ptr); + + ratio = ((gdouble)SCALEDEST(gdisp))/((gdouble)SCALESRC(gdisp)); + + hbox = gtk_hbox_new(FALSE,0); + iwd->previewBox = hbox; + gtk_widget_show(hbox); + gtk_container_add(GTK_CONTAINER (iwd->previewAlign),hbox); + + image = gtk_preview_new (GTK_PREVIEW_COLOR); + iwd->preview = image; + gtk_widget_show (image); + + gtk_preview_set_dither (GTK_PREVIEW (image), GDK_RGB_DITHER_MAX); + gtk_widget_set_events( GTK_WIDGET(image), PREVIEW_MASK ); + + set_size_data(iwd); + + gtk_preview_size (GTK_PREVIEW (iwd->preview), + iwd->pwidth, + iwd->pheight); + + gtk_widget_set_usize (iwd->preview, + iwd->pwidth, + iwd->pheight); + + frame = gtk_frame_new(NULL); + gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN); + gtk_container_add(GTK_CONTAINER (iwd->previewBox),frame); + gtk_container_add (GTK_CONTAINER (frame), iwd->preview); + gtk_widget_show(frame); + + iwd->sig_hand_id = gtk_signal_connect_after (GTK_OBJECT (image), "expose_event", + (GtkSignalFunc) nav_window_expose_events, + iwd); + + gtk_signal_connect (GTK_OBJECT (image), "event", + (GtkSignalFunc) nav_window_preview_events, + iwd); + +/* gtk_signal_connect (GTK_OBJECT (image), "size_allocate", */ +/* (GtkSignalFunc) nav_window_preview_resized, */ +/* iwd); */ + + gtk_widget_grab_focus(image); + +} + +#if 0 +static void +info_window_page_switch (GtkWidget *widget, + GtkNotebookPage *page, + gint page_num) +{ + InfoDialog *info_win; + InfoWinData *iwd; + + info_win = (InfoDialog *)gtk_object_get_user_data(GTK_OBJECT (widget)); + iwd = (InfoWinData *)info_win->user_data; + + /* Only deal with the second page */ + if(page_num != 1) + { + iwd->showingPreview = FALSE; + return; + } + + iwd->showingPreview = TRUE; + +} +#endif /* 0 */ + +static void +update_real_view(NavWinData *iwd,gint tx,gint ty) +{ + GDisplay *gdisp; + gdouble ratio; + gint xoffset; + gint yoffset; + + gdisp = (GDisplay *) iwd->gdisp_ptr; + ratio = ((gdouble)SCALEDEST(gdisp))/((gdouble)SCALESRC(gdisp)); + + xoffset = tx - iwd->dispx; + yoffset = ty - iwd->dispy; + + xoffset = (gint)(((gdouble)xoffset*ratio)/iwd->ratio); + yoffset = (gint)(((gdouble)yoffset*ratio)/iwd->ratio); + + iwd->block_window_marker = TRUE; + scroll_display(iwd->gdisp_ptr,xoffset,yoffset); + iwd->block_window_marker = FALSE; +} + +static void +nav_window_update_preview(NavWinData *iwd) +{ + GDisplay *gdisp; + TempBuf * preview_buf; + gchar *src, *buf; + gint x,y,has_alpha; + gint pwidth, pheight; + GimpImage *gimage; + gdisp = (GDisplay *) iwd->gdisp_ptr; + + /* Calculate preview size */ + gimage = ((GDisplay *)(iwd->gdisp_ptr))->gimage; + + /* Min size is 2 */ + pwidth = iwd->pwidth; + pheight = iwd->pheight; + + preview_buf = gimp_image_construct_composite_preview (gimage, + MAX (pwidth, 2), + MAX (pheight, 2)); + + buf = g_new (gchar, iwd->nav_preview_width * 3); + src = (gchar *) temp_buf_data (preview_buf); + has_alpha = (preview_buf->bytes == 2 || preview_buf->bytes == 4); + for (y = 0; y height ; y++) + { + if (preview_buf->bytes == (1+has_alpha)) + for (x = 0; x < preview_buf->width; x++) + { + buf[x*3+0] = src[x]; + buf[x*3+1] = src[x]; + buf[x*3+2] = src[x]; + } + else + for (x = 0; x < preview_buf->width; x++) + { + gint stride = 3 + has_alpha; + buf[x*3+0] = src[x*stride+0]; + buf[x*3+1] = src[x*stride+1]; + buf[x*3+2] = src[x*stride+2]; + } + gtk_preview_draw_row (GTK_PREVIEW (iwd->preview), + (guchar *)buf, 0, y, preview_buf->width); + src += preview_buf->width * preview_buf->bytes; + } + + g_free (buf); + temp_buf_free (preview_buf); + + nav_window_disp_area(iwd,gdisp); +} + +static gint +inside_preview_square(NavWinData *iwd, gint x, gint y) +{ + if(x > iwd->dispx && + x < (iwd->dispx + iwd->dispwidth) && + y > iwd->dispy && + y < iwd->dispy + iwd->dispheight) + return TRUE; + + return FALSE; +} + +#if 0 +static gint +nav_window_preview_resized (GtkWidget *widget, + GtkAllocation *alloc, + gpointer *data) +{ + NavWinData *iwd; + + iwd = (NavWinData *)data; + + if(!iwd || !iwd->preview) + return FALSE; + + printf("Now at [x,y] = [%d,%d] [w,h] = [%d,%d]\n", + alloc->x,alloc->y, + alloc->width,alloc->height); + + if(iwd->nav_preview_width == alloc->width && + iwd->nav_preview_height == alloc->height) + return FALSE; + + iwd->nav_preview_width = alloc->width; + iwd->nav_preview_height = alloc->height; + set_size_data(iwd); + gtk_preview_size(GTK_PREVIEW(iwd->preview),alloc->width,alloc->height); + nav_window_update_preview(iwd); + nav_window_draw_sqr(iwd,FALSE, + iwd->dispx,iwd->dispy, + iwd->dispwidth,iwd->dispheight); + +#if 0 + destroy_preview_widget(iwd); + create_preview_widget(iwd); + nav_window_update_preview(iwd); + + + nav_window_update_preview(iwd); + gtk_widget_show(iwd->preview); + gtk_widget_draw(iwd->preview, NULL); + gtk_widget_show(iwd->previewAlign); + nav_window_draw_sqr(iwd,FALSE, + iwd->dispx,iwd->dispy, + iwd->dispwidth,iwd->dispheight); + +#endif /* 0 */ + return FALSE; +} + +#endif /* 0 */ + +static gint +nav_window_preview_events (GtkWidget *widget, + GdkEvent *event, + gpointer *data) +{ + NavWinData *iwd; + GDisplay *gdisp; + GdkEventButton *bevent; + GdkEventMotion *mevent; + gint tx,ty; + + iwd = (NavWinData *)data; + + if(!iwd) + return FALSE; + + gdisp = (GDisplay *) iwd->gdisp_ptr; + + switch (event->type) + { + case GDK_EXPOSE: + break; + + case GDK_MAP: + nav_window_update_preview(iwd); + break; + + case GDK_BUTTON_PRESS: + bevent = (GdkEventButton *) event; + tx = bevent->x; + ty = bevent->y; + + /* Must start the move */ + + switch (bevent->button) + { + case 1: + if(inside_preview_square(iwd,tx,ty)) + { + iwd->motion_offsetx = tx - iwd->dispx; + iwd->motion_offsety = ty - iwd->dispy; + iwd->sq_grabbed = TRUE; + gtk_grab_add(widget); + } + else + { + /* Direct scroll to the location */ + /* view scrolled to the center or nearest possible point */ + + tx -= iwd->dispwidth/2; + ty -= iwd->dispheight/2; + + if(tx < 0) + tx = 0; + + if((tx + iwd->dispwidth) > iwd->pwidth) + tx = iwd->pwidth - iwd->dispwidth; + + if(ty < 0) + ty = 0; + + if((ty + iwd->dispheight) > iwd->pheight) + ty = iwd->pheight - iwd->dispheight; + + update_real_view(iwd,tx,ty); + + nav_window_draw_sqr(iwd, + TRUE, + tx,ty, + iwd->dispwidth,iwd->dispheight); + } + break; + default: + } + break; + + case GDK_BUTTON_RELEASE: + bevent = (GdkEventButton *) event; + tx = bevent->x; + ty = bevent->y; + + switch (bevent->button) + { + case 1: + iwd->sq_grabbed = FALSE; + gtk_grab_remove(widget); + break; + default: + } + break; + + case GDK_MOTION_NOTIFY: + mevent = (GdkEventMotion *) event; + + if(!iwd->sq_grabbed) + break; + + tx = mevent->x; + ty = mevent->y; + + if(tx < 0) + { + tx = 0; + } + + if(tx > iwd->pwidth) + { + tx = iwd->pwidth; + } + + if(ty < 0) + { + ty = 0; + } + + if(ty > iwd->pheight) + { + ty = iwd->pwidth; + } + + tx = tx - iwd->motion_offsetx; + ty = ty - iwd->motion_offsety; + + if(tx < 0 || (tx + iwd->dispwidth) >= iwd->pwidth) + { + iwd->motion_offsetx = mevent->x - iwd->dispx; + tx = iwd->dispx; + } + + if(ty < 0 || (ty + iwd->dispheight) >= iwd->pheight) + { + iwd->motion_offsety = mevent->y - iwd->dispy; + ty = iwd->dispy; + } + + /* Update the real display */ + update_real_view(iwd,tx,ty); + + nav_window_draw_sqr(iwd, + TRUE, + tx,ty, + iwd->dispwidth,iwd->dispheight); + + break; + + default: + break; + } + + return FALSE; +} + +static gint +nav_window_expose_events (GtkWidget *widget, + GdkEvent *event, + gpointer *data) +{ + NavWinData *iwd; + GDisplay *gdisp; + + iwd = (NavWinData *)data; + + if(!iwd) + return FALSE; + + gdisp = (GDisplay *) iwd->gdisp_ptr; + + switch (event->type) + { + case GDK_EXPOSE: + gtk_signal_handler_block(GTK_OBJECT(widget),iwd->sig_hand_id); + gtk_widget_draw(iwd->preview, NULL); + gtk_signal_handler_unblock(GTK_OBJECT(widget),iwd->sig_hand_id ); + + nav_window_draw_sqr(iwd,FALSE, + iwd->dispx,iwd->dispy, + iwd->dispwidth,iwd->dispheight); + + break; + case GDK_KEY_PRESS: + /* hack for the update preview... needs to be fixed */ + nav_window_update_preview(iwd); + gtk_widget_draw(iwd->preview, NULL); + break; + default: + break; + } + + return FALSE; +} + + +static GtkWidget * +info_window_image_preview_new(InfoDialog *info_win) +{ + GtkWidget *hbox1; + GtkWidget *alignment; + + NavWinData *iwd; + + iwd = (NavWinData *)info_win->user_data; + + hbox1 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox1); + + gtk_widget_realize(info_win->shell); + + /* need gc to draw the preview sqr with */ + iwd->gc = gdk_gc_new(info_win->shell->window); + gdk_gc_set_function (iwd->gc, GDK_INVERT); + gdk_gc_set_line_attributes (iwd->gc, BORDER_PEN_WIDTH, GDK_LINE_SOLID, + GDK_CAP_BUTT, GDK_JOIN_ROUND); + + alignment = gtk_alignment_new(0.5,0.5,0.0,0.0); + iwd->previewAlign = alignment; + gtk_widget_show (alignment); + + /* Create the preview in which to draw the thumbnail image */ + + create_preview_widget(iwd); + + gtk_box_pack_start (GTK_BOX (hbox1), alignment, TRUE, TRUE, 0); + + return hbox1; +} + +static ActionAreaItem action_items[] = +{ + { N_("Close"), nav_window_close_callback, NULL, NULL }, +}; + +InfoDialog * +nav_window_create (void *gdisp_ptr) +{ + InfoDialog *info_win; + GDisplay *gdisp; + NavWinData *iwd; + GtkWidget *container; + char *title; + char *title_buf; + int type; + + gdisp = (GDisplay *) gdisp_ptr; + + title = g_basename (gimage_filename (gdisp->gimage)); + type = gimage_base_type (gdisp->gimage); + + /* create the info dialog */ + title_buf = g_strdup_printf (_("%s: Window Navigation"), title); + info_win = info_dialog_new (title_buf); + g_free (title_buf); +/* gtk_window_set_policy (GTK_WINDOW (info_win->shell), */ +/* FALSE,FALSE,FALSE); */ + + iwd = (NavWinData *) g_malloc (sizeof (NavWinData)); + info_win->user_data = iwd; + iwd->showingPreview = TRUE; + iwd->preview = NULL; + iwd->gdisp_ptr = gdisp_ptr; + iwd->dispx = -1; + iwd->dispy = -1; + iwd->dispwidth = -1; + iwd->dispheight = -1; + iwd->imagewidth = -1; + iwd->imageheight = -1; + iwd->sq_grabbed = FALSE; + iwd->ratio = 1.0; + iwd->block_window_marker = FALSE; + iwd->nav_preview_width = NAV_PREVIEW_WIDTH; + iwd->nav_preview_height = NAV_PREVIEW_HEIGHT; + + /* Add preview */ + container = info_window_image_preview_new(info_win); + gtk_table_attach_defaults (GTK_TABLE (info_win->info_table), container, + 0, 2, 0, 1); + /* Create the action area */ + action_items[0].user_data = info_win; + build_action_area (GTK_DIALOG (info_win->shell), action_items, 1, 0); + + return info_win; +} + +void +nav_window_update_window_marker(InfoDialog *info_win) +{ + NavWinData *iwd; + + if(!info_win) + return; + + iwd = (NavWinData *)info_win->user_data; + + if(!iwd || + iwd->showingPreview == FALSE || + iwd->block_window_marker == TRUE) + return; + + /* Undraw old size */ + nav_window_draw_sqr(iwd, + FALSE, + iwd->dispx, + iwd->dispy, + iwd->dispwidth,iwd->dispheight); + + /* Update to new size */ + nav_window_disp_area(iwd,iwd->gdisp_ptr); + + /* and redraw */ + nav_window_draw_sqr(iwd, + FALSE, + iwd->dispx, + iwd->dispy, + iwd->dispwidth,iwd->dispheight); +} + +void +nav_window_free (InfoDialog *info_win) +{ + g_free (info_win->user_data); + info_dialog_free (info_win); +} diff --git a/app/gdisplay.c b/app/gdisplay.c index 14f6e14bba..20c4524f0b 100644 --- a/app/gdisplay.c +++ b/app/gdisplay.c @@ -35,6 +35,7 @@ #include "interface.h" #include "lc_dialog.h" #include "menus.h" +#include "nav_window.h" #include "plug_in.h" #include "qmask.h" #include "scale.h" @@ -97,6 +98,7 @@ gdisplay_new (GimpImage *gimage, gdisp->dot_for_dot = TRUE; gdisp->gimage = gimage; gdisp->window_info_dialog = NULL; + gdisp->window_nav_dialog = NULL; gdisp->depth = g_visual->depth; gdisp->select = NULL; gdisp->ID = display_num++; @@ -329,6 +331,10 @@ gdisplay_delete (GDisplay *gdisp) if (gdisp->window_info_dialog) info_window_free (gdisp->window_info_dialog); + /* Remove navigation dialog if we have one */ + if(gdisp->window_nav_dialog) + nav_window_free(gdisp->window_nav_dialog); + /* set the active display to NULL if it was this display */ context = gimp_context_get_user (); if (gimp_context_get_display (context) == gdisp) @@ -1010,7 +1016,7 @@ gdisplay_update_cursor (GDisplay *gdisp, int x, int y) } } - gdisplay_untransform_coords(gdisp, x, y, &t_x, &t_y, TRUE, TRUE); + gdisplay_untransform_coords(gdisp, x, y, &t_x, &t_y, FALSE, FALSE); active_drawable = gimp_image_active_drawable (gdisp->gimage); @@ -1022,6 +1028,10 @@ gdisplay_update_cursor (GDisplay *gdisp, int x, int y) t_y >= active_drawable->height) { gtk_label_set (GTK_LABEL (gdisp->cursor_label), ""); + info_window_update_RGB(gdisp->window_info_dialog, + gdisp, + -1, + -1); } else { @@ -1042,6 +1052,10 @@ gdisplay_update_cursor (GDisplay *gdisp, int x, int y) (double) t_y * unit_factor / gdisp->gimage->yresolution); } gtk_label_set (GTK_LABEL (gdisp->cursor_label), buffer); + info_window_update_RGB(gdisp->window_info_dialog, + gdisp, + t_x, + t_y); } } @@ -1051,6 +1065,7 @@ gdisplay_update_cursor (GDisplay *gdisp, int x, int y) if (new_cursor) gdisplay_flush (gdisp); + } diff --git a/app/gdisplay.h b/app/gdisplay.h index d528cc80da..eb63b65d2d 100644 --- a/app/gdisplay.h +++ b/app/gdisplay.h @@ -111,6 +111,7 @@ struct _GDisplay guint progressid; /* id of statusbar message for progress */ InfoDialog *window_info_dialog; /* dialog box for image information */ + InfoDialog *window_nav_dialog; /* dialog box for image navigation */ int color_type; /* is this an RGB or GRAY colormap */ diff --git a/app/gui/commands.c b/app/gui/commands.c index 0f140a5a81..dd2d4fc091 100644 --- a/app/gui/commands.c +++ b/app/gui/commands.c @@ -39,6 +39,7 @@ #include "gradient.h" #include "image_render.h" #include "info_window.h" +#include "nav_window.h" #include "interface.h" #include "invert.h" #include "lc_dialog.h" @@ -535,6 +536,19 @@ view_window_info_cmd_callback (GtkWidget *widget, info_dialog_popup (gdisp->window_info_dialog); } +void +view_window_nav_cmd_callback (GtkWidget *widget, + gpointer client_data) +{ + GDisplay * gdisp; + return_if_no_display (gdisp); + + if (! gdisp->window_nav_dialog) + gdisp->window_nav_dialog = nav_window_create ((void *) gdisp); + + info_dialog_popup (gdisp->window_nav_dialog); +} + void view_toggle_selection_cmd_callback (GtkWidget *widget, gpointer client_data) diff --git a/app/gui/commands.h b/app/gui/commands.h index 9088c09850..5b30d36060 100644 --- a/app/gui/commands.h +++ b/app/gui/commands.h @@ -51,6 +51,7 @@ void view_zoom_1_4_callback (GtkWidget *, gpointer); void view_zoom_1_8_callback (GtkWidget *, gpointer); void view_zoom_1_16_callback (GtkWidget *, gpointer); void view_window_info_cmd_callback (GtkWidget *, gpointer); +void view_window_nav_cmd_callback (GtkWidget *, gpointer); void view_toggle_selection_cmd_callback (GtkWidget *, gpointer); void view_toggle_rulers_cmd_callback (GtkWidget *, gpointer); void view_toggle_guides_cmd_callback (GtkWidget *, gpointer); diff --git a/app/gui/help-commands.c b/app/gui/help-commands.c index 0f140a5a81..dd2d4fc091 100644 --- a/app/gui/help-commands.c +++ b/app/gui/help-commands.c @@ -39,6 +39,7 @@ #include "gradient.h" #include "image_render.h" #include "info_window.h" +#include "nav_window.h" #include "interface.h" #include "invert.h" #include "lc_dialog.h" @@ -535,6 +536,19 @@ view_window_info_cmd_callback (GtkWidget *widget, info_dialog_popup (gdisp->window_info_dialog); } +void +view_window_nav_cmd_callback (GtkWidget *widget, + gpointer client_data) +{ + GDisplay * gdisp; + return_if_no_display (gdisp); + + if (! gdisp->window_nav_dialog) + gdisp->window_nav_dialog = nav_window_create ((void *) gdisp); + + info_dialog_popup (gdisp->window_nav_dialog); +} + void view_toggle_selection_cmd_callback (GtkWidget *widget, gpointer client_data) diff --git a/app/gui/help-commands.h b/app/gui/help-commands.h index 9088c09850..5b30d36060 100644 --- a/app/gui/help-commands.h +++ b/app/gui/help-commands.h @@ -51,6 +51,7 @@ void view_zoom_1_4_callback (GtkWidget *, gpointer); void view_zoom_1_8_callback (GtkWidget *, gpointer); void view_zoom_1_16_callback (GtkWidget *, gpointer); void view_window_info_cmd_callback (GtkWidget *, gpointer); +void view_window_nav_cmd_callback (GtkWidget *, gpointer); void view_toggle_selection_cmd_callback (GtkWidget *, gpointer); void view_toggle_rulers_cmd_callback (GtkWidget *, gpointer); void view_toggle_guides_cmd_callback (GtkWidget *, gpointer); diff --git a/app/gui/info-dialog.c b/app/gui/info-dialog.c index 696269404a..6b2a750eb5 100644 --- a/app/gui/info-dialog.c +++ b/app/gui/info-dialog.c @@ -139,15 +139,14 @@ info_dialog_delete_callback (GtkWidget *w, return TRUE; } -/* public functions */ - -InfoDialog * -info_dialog_new (char *title) +static InfoDialog * +info_dialog_new_extended (char *title,gboolean inNotebook) { InfoDialog *idialog; GtkWidget *shell; GtkWidget *vbox; GtkWidget *info_table; + GtkWidget *info_notebook; idialog = g_new (InfoDialog, 1); idialog->field_list = NULL; @@ -167,11 +166,28 @@ info_dialog_new (char *title) gtk_box_pack_start (GTK_BOX (GTK_DIALOG (shell)->vbox), vbox, TRUE, TRUE, 0); info_table = gtk_table_new (2, 0, FALSE); - gtk_box_pack_start (GTK_BOX (vbox), info_table, TRUE, TRUE, 0); + + if(inNotebook) + { + info_notebook = gtk_notebook_new(); + gtk_notebook_append_page(GTK_NOTEBOOK(info_notebook), + info_table, + gtk_label_new (_("General"))); + gtk_box_pack_start (GTK_BOX (vbox), info_notebook, TRUE, TRUE, 0); + } + else + { + info_notebook = NULL; + gtk_box_pack_start (GTK_BOX (vbox), info_table, TRUE, TRUE, 0); + } idialog->shell = shell; idialog->vbox = vbox; idialog->info_table = info_table; + idialog->info_notebook = info_notebook; + + if(inNotebook) + gtk_widget_show (idialog->info_notebook); gtk_widget_show (idialog->info_table); gtk_widget_show (idialog->vbox); @@ -179,6 +195,20 @@ info_dialog_new (char *title) return idialog; } +/* public functions */ + +InfoDialog * +info_dialog_notebook_new (char *title) +{ + return info_dialog_new_extended(title,TRUE); +} + +InfoDialog * +info_dialog_new (char *title) +{ + return info_dialog_new_extended(title,FALSE); +} + void info_dialog_free (InfoDialog *idialog) { diff --git a/app/gui/info-dialog.h b/app/gui/info-dialog.h index 457918c132..1443406252 100644 --- a/app/gui/info-dialog.h +++ b/app/gui/info-dialog.h @@ -50,6 +50,7 @@ struct _InfoDialog GtkWidget *shell; GtkWidget *vbox; GtkWidget *info_table; + GtkWidget *info_notebook; GSList *field_list; int nfields; @@ -60,6 +61,7 @@ struct _InfoDialog /* Info Dialog functions */ InfoDialog *info_dialog_new (gchar *title); +InfoDialog *info_dialog_notebook_new (gchar *title); void info_dialog_free (InfoDialog *idialog); void info_dialog_popup (InfoDialog *idialog); diff --git a/app/gui/info-window.c b/app/gui/info-window.c index 227ab5fad2..67e5b2685d 100644 --- a/app/gui/info-window.c +++ b/app/gui/info-window.c @@ -15,6 +15,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + #include "appenv.h" #include "actionarea.h" #include "colormaps.h" @@ -23,9 +24,12 @@ #include "gdisplay.h" #include "gximage.h" #include "interface.h" +#include "scroll.h" #include "libgimp/gimpintl.h" #include "libgimp/gimpunit.h" +#include "pixmaps/dropper.xpm" + #define MAX_BUF 256 @@ -40,6 +44,12 @@ struct _InfoWinData char shades_str[MAX_BUF]; char resolution_str[MAX_BUF]; char unit_str[MAX_BUF]; + void *gdisp_ptr; /* I'a not happy 'bout this one */ + GtkWidget *labelBvalue; + GtkWidget *labelGvalue; + GtkWidget *labelRvalue; + GtkWidget *labelAvalue; + gboolean showingPreview; }; /* The different classes of visuals */ @@ -104,6 +114,142 @@ info_window_close_callback (GtkWidget *widget, info_dialog_popdown ((InfoDialog *) client_data); } + +static void +info_window_page_switch (GtkWidget *widget, + GtkNotebookPage *page, + gint page_num) +{ + InfoDialog *info_win; + InfoWinData *iwd; + + info_win = (InfoDialog *)gtk_object_get_user_data(GTK_OBJECT (widget)); + iwd = (InfoWinData *)info_win->user_data; + + /* Only deal with the second page */ + if(page_num != 1) + { + iwd->showingPreview = FALSE; + return; + } + + iwd->showingPreview = TRUE; + +} + +static void +info_window_image_preview_book(InfoDialog *info_win) +{ + GtkWidget *hbox1; + GtkWidget *frame; + GtkWidget *alignment; + GtkWidget *table2; + GtkWidget *labelBvalue; + GtkWidget *labelGvalue; + GtkWidget *labelRvalue; + GtkWidget *labelAvalue; + GtkWidget *labelB; + GtkWidget *labelG; + GtkWidget *labelR; + GtkWidget *labelA; + GtkWidget *pixmapwid; + GdkPixmap *pixmap; + GdkBitmap *mask; + GtkStyle *style; + + InfoWinData *iwd; + + iwd = (InfoWinData *)info_win->user_data; + + hbox1 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox1); + + alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0); + gtk_widget_show (alignment); + + frame = gtk_frame_new(NULL); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (hbox1), alignment, TRUE, TRUE, 0); + + table2 = gtk_table_new (5, 2, TRUE); + gtk_container_border_width (GTK_CONTAINER (table2), 2); + gtk_widget_show (table2); + gtk_container_add (GTK_CONTAINER (frame), table2); + gtk_container_add (GTK_CONTAINER (alignment), frame); + + labelAvalue = gtk_label_new ("N/A"); + gtk_widget_show (labelAvalue); + gtk_table_attach (GTK_TABLE (table2), labelAvalue, 1, 2, 4, 5, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + + labelBvalue = gtk_label_new ("N/A"); + gtk_widget_show (labelBvalue); + gtk_table_attach (GTK_TABLE (table2), labelBvalue, 1, 2, 3, 4, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + + labelGvalue = gtk_label_new ("N/A"); + gtk_widget_show (labelGvalue); + gtk_table_attach (GTK_TABLE (table2), labelGvalue, 1, 2, 2, 3, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + + labelRvalue = gtk_label_new ("N/A"); + gtk_widget_show (labelRvalue); + gtk_table_attach (GTK_TABLE (table2), labelRvalue, 1, 2, 1, 2, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + + labelA = gtk_label_new ("A:"); + gtk_widget_show (labelA); + gtk_table_attach (GTK_TABLE (table2), labelA, 0, 1, 4, 5, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + + labelB = gtk_label_new ("B:"); + gtk_widget_show (labelB); + gtk_table_attach (GTK_TABLE (table2), labelB, 0, 1, 3, 4, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + + labelG = gtk_label_new ("G:"); + gtk_widget_show (labelG); + gtk_table_attach (GTK_TABLE (table2), labelG, 0, 1, 2, 3, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + + labelR = gtk_label_new ("R:"); + gtk_widget_show (labelR); + gtk_table_attach (GTK_TABLE (table2), labelR, 0, 1, 1, 2, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + + gtk_widget_realize(info_win->shell); + style = gtk_widget_get_style (info_win->shell); + + pixmap = gdk_pixmap_create_from_xpm_d (info_win->shell->window, &mask, + &style->bg[GTK_STATE_NORMAL], + dropper_xpm); + pixmapwid = gtk_pixmap_new (pixmap, mask); + + gtk_misc_set_alignment (GTK_MISC (pixmapwid), 0.2, 0.2); + gtk_table_attach (GTK_TABLE (table2), pixmapwid, 0, 2, 0, 1, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (pixmapwid); + + gtk_notebook_append_page(GTK_NOTEBOOK(info_win->info_notebook), + hbox1, + gtk_label_new (_("Extended"))); + + /* Set back to first page */ + gtk_notebook_set_page(GTK_NOTEBOOK(info_win->info_notebook),0); + + gtk_object_set_user_data(GTK_OBJECT (info_win->info_notebook), + (gpointer)info_win); + + gtk_signal_connect (GTK_OBJECT (info_win->info_notebook), "switch_page", + GTK_SIGNAL_FUNC (info_window_page_switch), NULL); + + iwd->labelBvalue = labelBvalue; + iwd->labelGvalue = labelGvalue; + iwd->labelRvalue = labelRvalue; + iwd->labelAvalue = labelAvalue; + +} + /* displays information: * image name * image width, height @@ -136,7 +282,7 @@ info_window_create (void *gdisp_ptr) /* create the info dialog */ title_buf = g_strdup_printf (_("%s: Window Info"), title); - info_win = info_dialog_new (title_buf); + info_win = info_dialog_notebook_new (title_buf); g_free (title_buf); iwd = (InfoWinData *) g_malloc (sizeof (InfoWinData)); @@ -149,6 +295,7 @@ info_window_create (void *gdisp_ptr) iwd->visual_class_str[0] = '\0'; iwd->visual_depth_str[0] = '\0'; iwd->shades_str[0] = '\0'; + iwd->showingPreview = FALSE; /* add the information fields */ info_dialog_add_label (info_win, _("Dimensions (w x h):"), @@ -178,6 +325,9 @@ info_window_create (void *gdisp_ptr) /* update the fields */ info_window_update (info_win, gdisp_ptr); + /* Add extra tabs */ + info_window_image_preview_book(info_win); + /* Create the action area */ action_items[0].user_data = info_win; build_action_area (GTK_DIALOG (info_win->shell), action_items, 1, 0); @@ -185,6 +335,61 @@ info_window_create (void *gdisp_ptr) return info_win; } +void +info_window_update_RGB (InfoDialog *info_win, + void *gdisp_ptr, + gdouble tx, + gdouble ty) +{ + GDisplay *gdisp; + InfoWinData *iwd; + char buff[5]; + guchar *color; + gint has_alpha; + gint sample_type; + + if(!info_win) + return; + + gdisp = (GDisplay *) gdisp_ptr; + iwd = (InfoWinData *) info_win->user_data; + + if(!iwd || iwd->showingPreview == FALSE) + return; + + /* gimage_active_drawable (gdisp->gimage) */ + if (!(color = gimp_image_get_color_at(gdisp->gimage, tx, ty)) + || (tx < 0.0 && ty < 0.0)) + { + g_snprintf(buff,5,"%4s","N/A"); + gtk_label_set_text(GTK_LABEL(iwd->labelBvalue),buff); + gtk_label_set_text(GTK_LABEL(iwd->labelGvalue),buff); + gtk_label_set_text(GTK_LABEL(iwd->labelRvalue),buff); + gtk_label_set_text(GTK_LABEL(iwd->labelAvalue),buff); + + return; + } + + g_snprintf(buff,5,"%4d",(gint)color[BLUE_PIX]); + gtk_label_set_text(GTK_LABEL(iwd->labelBvalue),buff); + g_snprintf(buff,5,"%4d",(gint)color[GREEN_PIX]); + gtk_label_set_text(GTK_LABEL(iwd->labelGvalue),buff); + g_snprintf(buff,5,"%4d",(gint)color[RED_PIX]); + gtk_label_set_text(GTK_LABEL(iwd->labelRvalue),buff); + + sample_type = gimp_image_composite_type (gdisp->gimage); + has_alpha = TYPE_HAS_ALPHA (sample_type); + + if(has_alpha) + g_snprintf(buff,5,"%4d",(gint)color[ALPHA_PIX]); + else + g_snprintf(buff,5,"%4s","N/A"); + + gtk_label_set_text(GTK_LABEL(iwd->labelAvalue),buff); + + g_free(color); +} + void info_window_free (InfoDialog *info_win) { diff --git a/app/gui/info-window.h b/app/gui/info-window.h index a568c3ecf2..7ca4fae600 100644 --- a/app/gui/info-window.h +++ b/app/gui/info-window.h @@ -23,6 +23,9 @@ InfoDialog *info_window_create (void *); void info_window_free (InfoDialog *); void info_window_update (InfoDialog *, void *); - +void info_window_update_RGB (InfoDialog *, + void *, + gdouble, + gdouble); #endif /* __INFO_WINDOW_H__ */ diff --git a/app/gui/menus.c b/app/gui/menus.c index 410a1d6b42..cec1ad6531 100644 --- a/app/gui/menus.c +++ b/app/gui/menus.c @@ -143,6 +143,7 @@ static GtkItemFactoryEntry image_entries[] = { N_("/View/Zoom/1:16"), NULL, view_zoom_1_16_callback, 0 }, { N_("/View/Dot for dot"), NULL, view_dot_for_dot_callback, 0, ""}, { N_("/View/Window Info..."), "I", view_window_info_cmd_callback, 0 }, + { N_("/View/Window Nav..."), NULL, view_window_nav_cmd_callback, 0 }, { N_("/View/---"), NULL, NULL, 0, "" }, { N_("/View/Toggle Selection"), "T", view_toggle_selection_cmd_callback, 0, "" }, diff --git a/app/info_dialog.c b/app/info_dialog.c index 696269404a..6b2a750eb5 100644 --- a/app/info_dialog.c +++ b/app/info_dialog.c @@ -139,15 +139,14 @@ info_dialog_delete_callback (GtkWidget *w, return TRUE; } -/* public functions */ - -InfoDialog * -info_dialog_new (char *title) +static InfoDialog * +info_dialog_new_extended (char *title,gboolean inNotebook) { InfoDialog *idialog; GtkWidget *shell; GtkWidget *vbox; GtkWidget *info_table; + GtkWidget *info_notebook; idialog = g_new (InfoDialog, 1); idialog->field_list = NULL; @@ -167,11 +166,28 @@ info_dialog_new (char *title) gtk_box_pack_start (GTK_BOX (GTK_DIALOG (shell)->vbox), vbox, TRUE, TRUE, 0); info_table = gtk_table_new (2, 0, FALSE); - gtk_box_pack_start (GTK_BOX (vbox), info_table, TRUE, TRUE, 0); + + if(inNotebook) + { + info_notebook = gtk_notebook_new(); + gtk_notebook_append_page(GTK_NOTEBOOK(info_notebook), + info_table, + gtk_label_new (_("General"))); + gtk_box_pack_start (GTK_BOX (vbox), info_notebook, TRUE, TRUE, 0); + } + else + { + info_notebook = NULL; + gtk_box_pack_start (GTK_BOX (vbox), info_table, TRUE, TRUE, 0); + } idialog->shell = shell; idialog->vbox = vbox; idialog->info_table = info_table; + idialog->info_notebook = info_notebook; + + if(inNotebook) + gtk_widget_show (idialog->info_notebook); gtk_widget_show (idialog->info_table); gtk_widget_show (idialog->vbox); @@ -179,6 +195,20 @@ info_dialog_new (char *title) return idialog; } +/* public functions */ + +InfoDialog * +info_dialog_notebook_new (char *title) +{ + return info_dialog_new_extended(title,TRUE); +} + +InfoDialog * +info_dialog_new (char *title) +{ + return info_dialog_new_extended(title,FALSE); +} + void info_dialog_free (InfoDialog *idialog) { diff --git a/app/info_dialog.h b/app/info_dialog.h index 457918c132..1443406252 100644 --- a/app/info_dialog.h +++ b/app/info_dialog.h @@ -50,6 +50,7 @@ struct _InfoDialog GtkWidget *shell; GtkWidget *vbox; GtkWidget *info_table; + GtkWidget *info_notebook; GSList *field_list; int nfields; @@ -60,6 +61,7 @@ struct _InfoDialog /* Info Dialog functions */ InfoDialog *info_dialog_new (gchar *title); +InfoDialog *info_dialog_notebook_new (gchar *title); void info_dialog_free (InfoDialog *idialog); void info_dialog_popup (InfoDialog *idialog); diff --git a/app/info_window.c b/app/info_window.c index 227ab5fad2..67e5b2685d 100644 --- a/app/info_window.c +++ b/app/info_window.c @@ -15,6 +15,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + #include "appenv.h" #include "actionarea.h" #include "colormaps.h" @@ -23,9 +24,12 @@ #include "gdisplay.h" #include "gximage.h" #include "interface.h" +#include "scroll.h" #include "libgimp/gimpintl.h" #include "libgimp/gimpunit.h" +#include "pixmaps/dropper.xpm" + #define MAX_BUF 256 @@ -40,6 +44,12 @@ struct _InfoWinData char shades_str[MAX_BUF]; char resolution_str[MAX_BUF]; char unit_str[MAX_BUF]; + void *gdisp_ptr; /* I'a not happy 'bout this one */ + GtkWidget *labelBvalue; + GtkWidget *labelGvalue; + GtkWidget *labelRvalue; + GtkWidget *labelAvalue; + gboolean showingPreview; }; /* The different classes of visuals */ @@ -104,6 +114,142 @@ info_window_close_callback (GtkWidget *widget, info_dialog_popdown ((InfoDialog *) client_data); } + +static void +info_window_page_switch (GtkWidget *widget, + GtkNotebookPage *page, + gint page_num) +{ + InfoDialog *info_win; + InfoWinData *iwd; + + info_win = (InfoDialog *)gtk_object_get_user_data(GTK_OBJECT (widget)); + iwd = (InfoWinData *)info_win->user_data; + + /* Only deal with the second page */ + if(page_num != 1) + { + iwd->showingPreview = FALSE; + return; + } + + iwd->showingPreview = TRUE; + +} + +static void +info_window_image_preview_book(InfoDialog *info_win) +{ + GtkWidget *hbox1; + GtkWidget *frame; + GtkWidget *alignment; + GtkWidget *table2; + GtkWidget *labelBvalue; + GtkWidget *labelGvalue; + GtkWidget *labelRvalue; + GtkWidget *labelAvalue; + GtkWidget *labelB; + GtkWidget *labelG; + GtkWidget *labelR; + GtkWidget *labelA; + GtkWidget *pixmapwid; + GdkPixmap *pixmap; + GdkBitmap *mask; + GtkStyle *style; + + InfoWinData *iwd; + + iwd = (InfoWinData *)info_win->user_data; + + hbox1 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox1); + + alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0); + gtk_widget_show (alignment); + + frame = gtk_frame_new(NULL); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (hbox1), alignment, TRUE, TRUE, 0); + + table2 = gtk_table_new (5, 2, TRUE); + gtk_container_border_width (GTK_CONTAINER (table2), 2); + gtk_widget_show (table2); + gtk_container_add (GTK_CONTAINER (frame), table2); + gtk_container_add (GTK_CONTAINER (alignment), frame); + + labelAvalue = gtk_label_new ("N/A"); + gtk_widget_show (labelAvalue); + gtk_table_attach (GTK_TABLE (table2), labelAvalue, 1, 2, 4, 5, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + + labelBvalue = gtk_label_new ("N/A"); + gtk_widget_show (labelBvalue); + gtk_table_attach (GTK_TABLE (table2), labelBvalue, 1, 2, 3, 4, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + + labelGvalue = gtk_label_new ("N/A"); + gtk_widget_show (labelGvalue); + gtk_table_attach (GTK_TABLE (table2), labelGvalue, 1, 2, 2, 3, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + + labelRvalue = gtk_label_new ("N/A"); + gtk_widget_show (labelRvalue); + gtk_table_attach (GTK_TABLE (table2), labelRvalue, 1, 2, 1, 2, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + + labelA = gtk_label_new ("A:"); + gtk_widget_show (labelA); + gtk_table_attach (GTK_TABLE (table2), labelA, 0, 1, 4, 5, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + + labelB = gtk_label_new ("B:"); + gtk_widget_show (labelB); + gtk_table_attach (GTK_TABLE (table2), labelB, 0, 1, 3, 4, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + + labelG = gtk_label_new ("G:"); + gtk_widget_show (labelG); + gtk_table_attach (GTK_TABLE (table2), labelG, 0, 1, 2, 3, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + + labelR = gtk_label_new ("R:"); + gtk_widget_show (labelR); + gtk_table_attach (GTK_TABLE (table2), labelR, 0, 1, 1, 2, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + + gtk_widget_realize(info_win->shell); + style = gtk_widget_get_style (info_win->shell); + + pixmap = gdk_pixmap_create_from_xpm_d (info_win->shell->window, &mask, + &style->bg[GTK_STATE_NORMAL], + dropper_xpm); + pixmapwid = gtk_pixmap_new (pixmap, mask); + + gtk_misc_set_alignment (GTK_MISC (pixmapwid), 0.2, 0.2); + gtk_table_attach (GTK_TABLE (table2), pixmapwid, 0, 2, 0, 1, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (pixmapwid); + + gtk_notebook_append_page(GTK_NOTEBOOK(info_win->info_notebook), + hbox1, + gtk_label_new (_("Extended"))); + + /* Set back to first page */ + gtk_notebook_set_page(GTK_NOTEBOOK(info_win->info_notebook),0); + + gtk_object_set_user_data(GTK_OBJECT (info_win->info_notebook), + (gpointer)info_win); + + gtk_signal_connect (GTK_OBJECT (info_win->info_notebook), "switch_page", + GTK_SIGNAL_FUNC (info_window_page_switch), NULL); + + iwd->labelBvalue = labelBvalue; + iwd->labelGvalue = labelGvalue; + iwd->labelRvalue = labelRvalue; + iwd->labelAvalue = labelAvalue; + +} + /* displays information: * image name * image width, height @@ -136,7 +282,7 @@ info_window_create (void *gdisp_ptr) /* create the info dialog */ title_buf = g_strdup_printf (_("%s: Window Info"), title); - info_win = info_dialog_new (title_buf); + info_win = info_dialog_notebook_new (title_buf); g_free (title_buf); iwd = (InfoWinData *) g_malloc (sizeof (InfoWinData)); @@ -149,6 +295,7 @@ info_window_create (void *gdisp_ptr) iwd->visual_class_str[0] = '\0'; iwd->visual_depth_str[0] = '\0'; iwd->shades_str[0] = '\0'; + iwd->showingPreview = FALSE; /* add the information fields */ info_dialog_add_label (info_win, _("Dimensions (w x h):"), @@ -178,6 +325,9 @@ info_window_create (void *gdisp_ptr) /* update the fields */ info_window_update (info_win, gdisp_ptr); + /* Add extra tabs */ + info_window_image_preview_book(info_win); + /* Create the action area */ action_items[0].user_data = info_win; build_action_area (GTK_DIALOG (info_win->shell), action_items, 1, 0); @@ -185,6 +335,61 @@ info_window_create (void *gdisp_ptr) return info_win; } +void +info_window_update_RGB (InfoDialog *info_win, + void *gdisp_ptr, + gdouble tx, + gdouble ty) +{ + GDisplay *gdisp; + InfoWinData *iwd; + char buff[5]; + guchar *color; + gint has_alpha; + gint sample_type; + + if(!info_win) + return; + + gdisp = (GDisplay *) gdisp_ptr; + iwd = (InfoWinData *) info_win->user_data; + + if(!iwd || iwd->showingPreview == FALSE) + return; + + /* gimage_active_drawable (gdisp->gimage) */ + if (!(color = gimp_image_get_color_at(gdisp->gimage, tx, ty)) + || (tx < 0.0 && ty < 0.0)) + { + g_snprintf(buff,5,"%4s","N/A"); + gtk_label_set_text(GTK_LABEL(iwd->labelBvalue),buff); + gtk_label_set_text(GTK_LABEL(iwd->labelGvalue),buff); + gtk_label_set_text(GTK_LABEL(iwd->labelRvalue),buff); + gtk_label_set_text(GTK_LABEL(iwd->labelAvalue),buff); + + return; + } + + g_snprintf(buff,5,"%4d",(gint)color[BLUE_PIX]); + gtk_label_set_text(GTK_LABEL(iwd->labelBvalue),buff); + g_snprintf(buff,5,"%4d",(gint)color[GREEN_PIX]); + gtk_label_set_text(GTK_LABEL(iwd->labelGvalue),buff); + g_snprintf(buff,5,"%4d",(gint)color[RED_PIX]); + gtk_label_set_text(GTK_LABEL(iwd->labelRvalue),buff); + + sample_type = gimp_image_composite_type (gdisp->gimage); + has_alpha = TYPE_HAS_ALPHA (sample_type); + + if(has_alpha) + g_snprintf(buff,5,"%4d",(gint)color[ALPHA_PIX]); + else + g_snprintf(buff,5,"%4s","N/A"); + + gtk_label_set_text(GTK_LABEL(iwd->labelAvalue),buff); + + g_free(color); +} + void info_window_free (InfoDialog *info_win) { diff --git a/app/info_window.h b/app/info_window.h index a568c3ecf2..7ca4fae600 100644 --- a/app/info_window.h +++ b/app/info_window.h @@ -23,6 +23,9 @@ InfoDialog *info_window_create (void *); void info_window_free (InfoDialog *); void info_window_update (InfoDialog *, void *); - +void info_window_update_RGB (InfoDialog *, + void *, + gdouble, + gdouble); #endif /* __INFO_WINDOW_H__ */ diff --git a/app/menus.c b/app/menus.c index 410a1d6b42..cec1ad6531 100644 --- a/app/menus.c +++ b/app/menus.c @@ -143,6 +143,7 @@ static GtkItemFactoryEntry image_entries[] = { N_("/View/Zoom/1:16"), NULL, view_zoom_1_16_callback, 0 }, { N_("/View/Dot for dot"), NULL, view_dot_for_dot_callback, 0, ""}, { N_("/View/Window Info..."), "I", view_window_info_cmd_callback, 0 }, + { N_("/View/Window Nav..."), NULL, view_window_nav_cmd_callback, 0 }, { N_("/View/---"), NULL, NULL, 0, "" }, { N_("/View/Toggle Selection"), "T", view_toggle_selection_cmd_callback, 0, "" }, diff --git a/app/menus/menus.c b/app/menus/menus.c index 410a1d6b42..cec1ad6531 100644 --- a/app/menus/menus.c +++ b/app/menus/menus.c @@ -143,6 +143,7 @@ static GtkItemFactoryEntry image_entries[] = { N_("/View/Zoom/1:16"), NULL, view_zoom_1_16_callback, 0 }, { N_("/View/Dot for dot"), NULL, view_dot_for_dot_callback, 0, ""}, { N_("/View/Window Info..."), "I", view_window_info_cmd_callback, 0 }, + { N_("/View/Window Nav..."), NULL, view_window_nav_cmd_callback, 0 }, { N_("/View/---"), NULL, NULL, 0, "" }, { N_("/View/Toggle Selection"), "T", view_toggle_selection_cmd_callback, 0, "" }, diff --git a/app/nav_window.c b/app/nav_window.c new file mode 100644 index 0000000000..67d3df2e02 --- /dev/null +++ b/app/nav_window.c @@ -0,0 +1,799 @@ +/* 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 "appenv.h" +#include "actionarea.h" +#include "colormaps.h" +#include "info_dialog.h" +#include "info_window.h" +#include "gdisplay.h" +#include "gximage.h" +#include "interface.h" +#include "scroll.h" + +#include "libgimp/gimpintl.h" +#include "libgimp/gimpunit.h" + + +#define MAX_BUF 256 + +#define PREVIEW_MASK GDK_EXPOSURE_MASK | \ + GDK_MOTION_NOTIFY | \ + GDK_POINTER_MOTION_MASK | \ + GDK_BUTTON_PRESS_MASK | \ + GDK_BUTTON_RELEASE_MASK | \ + GDK_BUTTON_MOTION_MASK | \ + GDK_KEY_PRESS_MASK | \ + GDK_KEY_RELEASE_MASK + +/* Navigation preview sizes */ +#define NAV_PREVIEW_WIDTH 112 +#define NAV_PREVIEW_HEIGHT 112 +#define BORDER_PEN_WIDTH 3 + +typedef struct _NavWinData NavWinData; +struct _NavWinData +{ + gboolean showingPreview; + GtkWidget *preview; + void *gdisp_ptr; /* I'a not happy 'bout this one */ + GtkWidget *previewBox; + GtkWidget *previewAlign; + gdouble ratio; + 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 left corner of display area */ + gint sig_hand_id; + 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 */ + gboolean block_window_marker; /* Block redraws of window marker */ + gint nav_preview_width; + gint nav_preview_height; +}; + + +static gint +nav_window_preview_events (GtkWidget *, + GdkEvent *, + gpointer *); +static gint +nav_window_expose_events (GtkWidget *, + GdkEvent *, + gpointer *); + +#if 0 +static gint +nav_window_preview_resized (GtkWidget *, + GtkAllocation *, + gpointer *); + +#endif /* 0 */ + +static void +nav_window_update_preview (NavWinData *); + +static void +destroy_preview_widget (NavWinData *); + +static void +create_preview_widget (NavWinData *); + +void +nav_window_update_window_marker(InfoDialog *); + +static void +nav_window_draw_sqr(NavWinData *, + gboolean, + gint , + gint , + gint , + gint ); + +static void +set_size_data(NavWinData *); + +static void +nav_window_close_callback (GtkWidget *widget, + gpointer client_data) +{ + InfoDialog *info_win; + NavWinData *iwd; + + info_win = (InfoDialog *)client_data; + iwd = (NavWinData *)info_win->user_data; + + /* iwd->showingPreview = FALSE; ALT. Needs to be sorted out */ + info_dialog_popdown ((InfoDialog *) client_data); +} + +static void +nav_window_disp_area(NavWinData *iwd,GDisplay *gdisp) +{ + GimpImage *gimage; + gint newwidth; + gint newheight; + gdouble ratio; /* Screen res ratio */ + gboolean need_update = FALSE; + + /* Calculate preview size */ + gimage = gdisp->gimage; + + ratio = ((gdouble)SCALEDEST(gdisp))/((gdouble)SCALESRC(gdisp)); + + iwd->dispx = gdisp->offset_x*iwd->ratio/ratio; + iwd->dispy = gdisp->offset_y*iwd->ratio/ratio; + iwd->dispwidth = (gdisp->disp_width*iwd->ratio)/ratio; + iwd->dispheight = (gdisp->disp_height*iwd->ratio)/ratio; + + newwidth = gimage->width; + newheight = gimage->height; + + if((iwd->imagewidth > 0 && newwidth != iwd->imagewidth) || + (iwd->imageheight > 0 && newheight != iwd->imageheight)) + { + /* Must change the preview size */ + destroy_preview_widget(iwd); + create_preview_widget(iwd); + need_update = TRUE; + } + + iwd->imagewidth = newwidth; + iwd->imageheight = newheight; + + /* Normalise */ + iwd->dispwidth = MIN(iwd->dispwidth, iwd->pwidth-BORDER_PEN_WIDTH); + iwd->dispheight = MIN(iwd->dispheight, iwd->pheight-BORDER_PEN_WIDTH); + + if(need_update == TRUE) + { + gtk_widget_hide(iwd->previewAlign); + nav_window_update_preview(iwd); + gtk_widget_show(iwd->preview); + gtk_widget_draw(iwd->preview, NULL); + gtk_widget_show(iwd->previewAlign); + nav_window_draw_sqr(iwd,FALSE, + iwd->dispx,iwd->dispy, + iwd->dispwidth,iwd->dispheight); + } +} + +static void +nav_window_draw_sqr(NavWinData *iwd, + gboolean undraw, + gint x, + gint y, + gint w, + gint h) +{ + GDisplay *gdisp; + + gdisp = (GDisplay *) iwd->gdisp_ptr; + + gdk_gc_set_function (iwd->gc, GDK_INVERT); + + + if(undraw) + { + /* first undraw from last co-ords */ + gdk_draw_rectangle (iwd->preview->window, iwd->gc, FALSE, + iwd->dispx,iwd->dispy, + iwd->dispwidth, + iwd->dispheight); + } + +/* gdk_draw_rectangle (iwd->preview->window, iwd->gc, FALSE, */ +/* 10,20, */ +/* 40,50); */ + + gdk_draw_rectangle (iwd->preview->window, iwd->gc, FALSE, + x,y, + w, + h); + + iwd->dispx = x; + iwd->dispy = y; + iwd->dispwidth = w; + iwd->dispheight = h; +} + +static void +destroy_preview_widget(NavWinData *iwd) +{ + if(!iwd->preview) + return; + + gtk_widget_hide(iwd->previewBox); + gtk_widget_destroy(iwd->previewBox); + iwd->previewBox = NULL; + iwd->preview = NULL; +} + +static void +set_size_data(NavWinData *iwd) +{ + gint sel_width, sel_height; + gint pwidth, pheight; + GDisplay *gdisp; + GimpImage *gimage; + + gdisp = (GDisplay *)(iwd->gdisp_ptr); + gimage = gdisp->gimage; + + sel_width = gimage->width; + sel_height = gimage->height; + + if (sel_width > sel_height) { + pwidth = MIN(sel_width, iwd->nav_preview_width); + pheight = sel_height * pwidth / sel_width; + iwd->ratio = (gdouble)pwidth / ((gdouble)sel_width); + } else { + pheight = MIN(sel_height, iwd->nav_preview_height); + pwidth = sel_width * pheight / sel_height; + iwd->ratio = (gdouble)pheight / ((gdouble)sel_height); + } + + iwd->pwidth = pwidth; + iwd->pheight = pheight; +} + +static void +create_preview_widget(NavWinData *iwd) +{ + GtkWidget *hbox; + GtkWidget *image; + GtkWidget *frame; + gdouble ratio; + GDisplay *gdisp; + + gdisp = (GDisplay *)(iwd->gdisp_ptr); + + ratio = ((gdouble)SCALEDEST(gdisp))/((gdouble)SCALESRC(gdisp)); + + hbox = gtk_hbox_new(FALSE,0); + iwd->previewBox = hbox; + gtk_widget_show(hbox); + gtk_container_add(GTK_CONTAINER (iwd->previewAlign),hbox); + + image = gtk_preview_new (GTK_PREVIEW_COLOR); + iwd->preview = image; + gtk_widget_show (image); + + gtk_preview_set_dither (GTK_PREVIEW (image), GDK_RGB_DITHER_MAX); + gtk_widget_set_events( GTK_WIDGET(image), PREVIEW_MASK ); + + set_size_data(iwd); + + gtk_preview_size (GTK_PREVIEW (iwd->preview), + iwd->pwidth, + iwd->pheight); + + gtk_widget_set_usize (iwd->preview, + iwd->pwidth, + iwd->pheight); + + frame = gtk_frame_new(NULL); + gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN); + gtk_container_add(GTK_CONTAINER (iwd->previewBox),frame); + gtk_container_add (GTK_CONTAINER (frame), iwd->preview); + gtk_widget_show(frame); + + iwd->sig_hand_id = gtk_signal_connect_after (GTK_OBJECT (image), "expose_event", + (GtkSignalFunc) nav_window_expose_events, + iwd); + + gtk_signal_connect (GTK_OBJECT (image), "event", + (GtkSignalFunc) nav_window_preview_events, + iwd); + +/* gtk_signal_connect (GTK_OBJECT (image), "size_allocate", */ +/* (GtkSignalFunc) nav_window_preview_resized, */ +/* iwd); */ + + gtk_widget_grab_focus(image); + +} + +#if 0 +static void +info_window_page_switch (GtkWidget *widget, + GtkNotebookPage *page, + gint page_num) +{ + InfoDialog *info_win; + InfoWinData *iwd; + + info_win = (InfoDialog *)gtk_object_get_user_data(GTK_OBJECT (widget)); + iwd = (InfoWinData *)info_win->user_data; + + /* Only deal with the second page */ + if(page_num != 1) + { + iwd->showingPreview = FALSE; + return; + } + + iwd->showingPreview = TRUE; + +} +#endif /* 0 */ + +static void +update_real_view(NavWinData *iwd,gint tx,gint ty) +{ + GDisplay *gdisp; + gdouble ratio; + gint xoffset; + gint yoffset; + + gdisp = (GDisplay *) iwd->gdisp_ptr; + ratio = ((gdouble)SCALEDEST(gdisp))/((gdouble)SCALESRC(gdisp)); + + xoffset = tx - iwd->dispx; + yoffset = ty - iwd->dispy; + + xoffset = (gint)(((gdouble)xoffset*ratio)/iwd->ratio); + yoffset = (gint)(((gdouble)yoffset*ratio)/iwd->ratio); + + iwd->block_window_marker = TRUE; + scroll_display(iwd->gdisp_ptr,xoffset,yoffset); + iwd->block_window_marker = FALSE; +} + +static void +nav_window_update_preview(NavWinData *iwd) +{ + GDisplay *gdisp; + TempBuf * preview_buf; + gchar *src, *buf; + gint x,y,has_alpha; + gint pwidth, pheight; + GimpImage *gimage; + gdisp = (GDisplay *) iwd->gdisp_ptr; + + /* Calculate preview size */ + gimage = ((GDisplay *)(iwd->gdisp_ptr))->gimage; + + /* Min size is 2 */ + pwidth = iwd->pwidth; + pheight = iwd->pheight; + + preview_buf = gimp_image_construct_composite_preview (gimage, + MAX (pwidth, 2), + MAX (pheight, 2)); + + buf = g_new (gchar, iwd->nav_preview_width * 3); + src = (gchar *) temp_buf_data (preview_buf); + has_alpha = (preview_buf->bytes == 2 || preview_buf->bytes == 4); + for (y = 0; y height ; y++) + { + if (preview_buf->bytes == (1+has_alpha)) + for (x = 0; x < preview_buf->width; x++) + { + buf[x*3+0] = src[x]; + buf[x*3+1] = src[x]; + buf[x*3+2] = src[x]; + } + else + for (x = 0; x < preview_buf->width; x++) + { + gint stride = 3 + has_alpha; + buf[x*3+0] = src[x*stride+0]; + buf[x*3+1] = src[x*stride+1]; + buf[x*3+2] = src[x*stride+2]; + } + gtk_preview_draw_row (GTK_PREVIEW (iwd->preview), + (guchar *)buf, 0, y, preview_buf->width); + src += preview_buf->width * preview_buf->bytes; + } + + g_free (buf); + temp_buf_free (preview_buf); + + nav_window_disp_area(iwd,gdisp); +} + +static gint +inside_preview_square(NavWinData *iwd, gint x, gint y) +{ + if(x > iwd->dispx && + x < (iwd->dispx + iwd->dispwidth) && + y > iwd->dispy && + y < iwd->dispy + iwd->dispheight) + return TRUE; + + return FALSE; +} + +#if 0 +static gint +nav_window_preview_resized (GtkWidget *widget, + GtkAllocation *alloc, + gpointer *data) +{ + NavWinData *iwd; + + iwd = (NavWinData *)data; + + if(!iwd || !iwd->preview) + return FALSE; + + printf("Now at [x,y] = [%d,%d] [w,h] = [%d,%d]\n", + alloc->x,alloc->y, + alloc->width,alloc->height); + + if(iwd->nav_preview_width == alloc->width && + iwd->nav_preview_height == alloc->height) + return FALSE; + + iwd->nav_preview_width = alloc->width; + iwd->nav_preview_height = alloc->height; + set_size_data(iwd); + gtk_preview_size(GTK_PREVIEW(iwd->preview),alloc->width,alloc->height); + nav_window_update_preview(iwd); + nav_window_draw_sqr(iwd,FALSE, + iwd->dispx,iwd->dispy, + iwd->dispwidth,iwd->dispheight); + +#if 0 + destroy_preview_widget(iwd); + create_preview_widget(iwd); + nav_window_update_preview(iwd); + + + nav_window_update_preview(iwd); + gtk_widget_show(iwd->preview); + gtk_widget_draw(iwd->preview, NULL); + gtk_widget_show(iwd->previewAlign); + nav_window_draw_sqr(iwd,FALSE, + iwd->dispx,iwd->dispy, + iwd->dispwidth,iwd->dispheight); + +#endif /* 0 */ + return FALSE; +} + +#endif /* 0 */ + +static gint +nav_window_preview_events (GtkWidget *widget, + GdkEvent *event, + gpointer *data) +{ + NavWinData *iwd; + GDisplay *gdisp; + GdkEventButton *bevent; + GdkEventMotion *mevent; + gint tx,ty; + + iwd = (NavWinData *)data; + + if(!iwd) + return FALSE; + + gdisp = (GDisplay *) iwd->gdisp_ptr; + + switch (event->type) + { + case GDK_EXPOSE: + break; + + case GDK_MAP: + nav_window_update_preview(iwd); + break; + + case GDK_BUTTON_PRESS: + bevent = (GdkEventButton *) event; + tx = bevent->x; + ty = bevent->y; + + /* Must start the move */ + + switch (bevent->button) + { + case 1: + if(inside_preview_square(iwd,tx,ty)) + { + iwd->motion_offsetx = tx - iwd->dispx; + iwd->motion_offsety = ty - iwd->dispy; + iwd->sq_grabbed = TRUE; + gtk_grab_add(widget); + } + else + { + /* Direct scroll to the location */ + /* view scrolled to the center or nearest possible point */ + + tx -= iwd->dispwidth/2; + ty -= iwd->dispheight/2; + + if(tx < 0) + tx = 0; + + if((tx + iwd->dispwidth) > iwd->pwidth) + tx = iwd->pwidth - iwd->dispwidth; + + if(ty < 0) + ty = 0; + + if((ty + iwd->dispheight) > iwd->pheight) + ty = iwd->pheight - iwd->dispheight; + + update_real_view(iwd,tx,ty); + + nav_window_draw_sqr(iwd, + TRUE, + tx,ty, + iwd->dispwidth,iwd->dispheight); + } + break; + default: + } + break; + + case GDK_BUTTON_RELEASE: + bevent = (GdkEventButton *) event; + tx = bevent->x; + ty = bevent->y; + + switch (bevent->button) + { + case 1: + iwd->sq_grabbed = FALSE; + gtk_grab_remove(widget); + break; + default: + } + break; + + case GDK_MOTION_NOTIFY: + mevent = (GdkEventMotion *) event; + + if(!iwd->sq_grabbed) + break; + + tx = mevent->x; + ty = mevent->y; + + if(tx < 0) + { + tx = 0; + } + + if(tx > iwd->pwidth) + { + tx = iwd->pwidth; + } + + if(ty < 0) + { + ty = 0; + } + + if(ty > iwd->pheight) + { + ty = iwd->pwidth; + } + + tx = tx - iwd->motion_offsetx; + ty = ty - iwd->motion_offsety; + + if(tx < 0 || (tx + iwd->dispwidth) >= iwd->pwidth) + { + iwd->motion_offsetx = mevent->x - iwd->dispx; + tx = iwd->dispx; + } + + if(ty < 0 || (ty + iwd->dispheight) >= iwd->pheight) + { + iwd->motion_offsety = mevent->y - iwd->dispy; + ty = iwd->dispy; + } + + /* Update the real display */ + update_real_view(iwd,tx,ty); + + nav_window_draw_sqr(iwd, + TRUE, + tx,ty, + iwd->dispwidth,iwd->dispheight); + + break; + + default: + break; + } + + return FALSE; +} + +static gint +nav_window_expose_events (GtkWidget *widget, + GdkEvent *event, + gpointer *data) +{ + NavWinData *iwd; + GDisplay *gdisp; + + iwd = (NavWinData *)data; + + if(!iwd) + return FALSE; + + gdisp = (GDisplay *) iwd->gdisp_ptr; + + switch (event->type) + { + case GDK_EXPOSE: + gtk_signal_handler_block(GTK_OBJECT(widget),iwd->sig_hand_id); + gtk_widget_draw(iwd->preview, NULL); + gtk_signal_handler_unblock(GTK_OBJECT(widget),iwd->sig_hand_id ); + + nav_window_draw_sqr(iwd,FALSE, + iwd->dispx,iwd->dispy, + iwd->dispwidth,iwd->dispheight); + + break; + case GDK_KEY_PRESS: + /* hack for the update preview... needs to be fixed */ + nav_window_update_preview(iwd); + gtk_widget_draw(iwd->preview, NULL); + break; + default: + break; + } + + return FALSE; +} + + +static GtkWidget * +info_window_image_preview_new(InfoDialog *info_win) +{ + GtkWidget *hbox1; + GtkWidget *alignment; + + NavWinData *iwd; + + iwd = (NavWinData *)info_win->user_data; + + hbox1 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox1); + + gtk_widget_realize(info_win->shell); + + /* need gc to draw the preview sqr with */ + iwd->gc = gdk_gc_new(info_win->shell->window); + gdk_gc_set_function (iwd->gc, GDK_INVERT); + gdk_gc_set_line_attributes (iwd->gc, BORDER_PEN_WIDTH, GDK_LINE_SOLID, + GDK_CAP_BUTT, GDK_JOIN_ROUND); + + alignment = gtk_alignment_new(0.5,0.5,0.0,0.0); + iwd->previewAlign = alignment; + gtk_widget_show (alignment); + + /* Create the preview in which to draw the thumbnail image */ + + create_preview_widget(iwd); + + gtk_box_pack_start (GTK_BOX (hbox1), alignment, TRUE, TRUE, 0); + + return hbox1; +} + +static ActionAreaItem action_items[] = +{ + { N_("Close"), nav_window_close_callback, NULL, NULL }, +}; + +InfoDialog * +nav_window_create (void *gdisp_ptr) +{ + InfoDialog *info_win; + GDisplay *gdisp; + NavWinData *iwd; + GtkWidget *container; + char *title; + char *title_buf; + int type; + + gdisp = (GDisplay *) gdisp_ptr; + + title = g_basename (gimage_filename (gdisp->gimage)); + type = gimage_base_type (gdisp->gimage); + + /* create the info dialog */ + title_buf = g_strdup_printf (_("%s: Window Navigation"), title); + info_win = info_dialog_new (title_buf); + g_free (title_buf); +/* gtk_window_set_policy (GTK_WINDOW (info_win->shell), */ +/* FALSE,FALSE,FALSE); */ + + iwd = (NavWinData *) g_malloc (sizeof (NavWinData)); + info_win->user_data = iwd; + iwd->showingPreview = TRUE; + iwd->preview = NULL; + iwd->gdisp_ptr = gdisp_ptr; + iwd->dispx = -1; + iwd->dispy = -1; + iwd->dispwidth = -1; + iwd->dispheight = -1; + iwd->imagewidth = -1; + iwd->imageheight = -1; + iwd->sq_grabbed = FALSE; + iwd->ratio = 1.0; + iwd->block_window_marker = FALSE; + iwd->nav_preview_width = NAV_PREVIEW_WIDTH; + iwd->nav_preview_height = NAV_PREVIEW_HEIGHT; + + /* Add preview */ + container = info_window_image_preview_new(info_win); + gtk_table_attach_defaults (GTK_TABLE (info_win->info_table), container, + 0, 2, 0, 1); + /* Create the action area */ + action_items[0].user_data = info_win; + build_action_area (GTK_DIALOG (info_win->shell), action_items, 1, 0); + + return info_win; +} + +void +nav_window_update_window_marker(InfoDialog *info_win) +{ + NavWinData *iwd; + + if(!info_win) + return; + + iwd = (NavWinData *)info_win->user_data; + + if(!iwd || + iwd->showingPreview == FALSE || + iwd->block_window_marker == TRUE) + return; + + /* Undraw old size */ + nav_window_draw_sqr(iwd, + FALSE, + iwd->dispx, + iwd->dispy, + iwd->dispwidth,iwd->dispheight); + + /* Update to new size */ + nav_window_disp_area(iwd,iwd->gdisp_ptr); + + /* and redraw */ + nav_window_draw_sqr(iwd, + FALSE, + iwd->dispx, + iwd->dispy, + iwd->dispwidth,iwd->dispheight); +} + +void +nav_window_free (InfoDialog *info_win) +{ + g_free (info_win->user_data); + info_dialog_free (info_win); +} diff --git a/app/nav_window.h b/app/nav_window.h new file mode 100644 index 0000000000..a276f3f082 --- /dev/null +++ b/app/nav_window.h @@ -0,0 +1,28 @@ +/* The GIMP -- an image manipulation program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * Copyright (C) 1999 Andy Thomas alt@gimp.org + * + * 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. + */ +#ifndef __NAV_WINDOW_H__ +#define __NAV_WINDOW_H__ + +#include "info_dialog.h" + +InfoDialog *nav_window_create (void *); +void nav_window_free (InfoDialog *); +void nav_window_update_window_marker(InfoDialog *); + +#endif /* __NAV_WINDOW_H__ */ diff --git a/app/scale.c b/app/scale.c index 9c73de328d..9fbdd08c47 100644 --- a/app/scale.c +++ b/app/scale.c @@ -21,7 +21,7 @@ #include "gdisplay.h" #include "gdisplay_ops.h" #include "gimprc.h" -#include "info_window.h" +#include "nav_window.h" #include "scale.h" #include "tools.h" @@ -257,4 +257,7 @@ setup_scale (GDisplay *gdisp) gtk_widget_draw (GTK_WIDGET (hruler), NULL); gtk_widget_draw (GTK_WIDGET (vruler), NULL); + + if (gdisp->window_nav_dialog) + nav_window_update_window_marker(gdisp->window_nav_dialog); } diff --git a/app/scroll.c b/app/scroll.c index 4d3088acee..26322e6343 100644 --- a/app/scroll.c +++ b/app/scroll.c @@ -21,6 +21,7 @@ #include "scroll.h" #include "cursorutil.h" #include "tools.h" +#include "nav_window.h" /* This is the delay before dithering begins @@ -28,9 +29,6 @@ */ #define DITHER_DELAY 250 /* milliseconds */ -/* Locally defined functions */ -static int scroll_display (GDisplay *, int, int); - /* STATIC variables */ /* These are the values of the initial pointer grab */ static int startx, starty; @@ -127,10 +125,10 @@ scroll_to_pointer_position (GDisplay *gdisp, } -static int +int scroll_display (GDisplay *gdisp, - int x_offset, - int y_offset) + gint x_offset, + gint y_offset) { int old_x, old_y; int src_x, src_y; @@ -201,6 +199,8 @@ scroll_display (GDisplay *gdisp, if (x_offset || y_offset) gdisplays_flush (); + if (gdisp->window_nav_dialog) + nav_window_update_window_marker(gdisp->window_nav_dialog); /* Make sure graphics expose events are processed before scrolling * again */ diff --git a/app/scroll.h b/app/scroll.h index 29876918fb..24b1525162 100644 --- a/app/scroll.h +++ b/app/scroll.h @@ -35,4 +35,8 @@ void end_grab_and_scroll (GDisplay *, GdkEventButton *); void grab_and_scroll (GDisplay *, GdkEventMotion *); void scroll_to_pointer_position (GDisplay *, GdkEventMotion *); +/* generic scroll-by-offset function */ +gint scroll_display (GDisplay *, gint, gint); + + #endif /* __SCROLL_H__ */ diff --git a/app/widgets/gimpitemfactory.c b/app/widgets/gimpitemfactory.c index 410a1d6b42..cec1ad6531 100644 --- a/app/widgets/gimpitemfactory.c +++ b/app/widgets/gimpitemfactory.c @@ -143,6 +143,7 @@ static GtkItemFactoryEntry image_entries[] = { N_("/View/Zoom/1:16"), NULL, view_zoom_1_16_callback, 0 }, { N_("/View/Dot for dot"), NULL, view_dot_for_dot_callback, 0, ""}, { N_("/View/Window Info..."), "I", view_window_info_cmd_callback, 0 }, + { N_("/View/Window Nav..."), NULL, view_window_nav_cmd_callback, 0 }, { N_("/View/---"), NULL, NULL, 0, "" }, { N_("/View/Toggle Selection"), "T", view_toggle_selection_cmd_callback, 0, "" }, diff --git a/pixmaps/dropper.xpm b/pixmaps/dropper.xpm new file mode 100644 index 0000000000..bf434f6a84 --- /dev/null +++ b/pixmaps/dropper.xpm @@ -0,0 +1,28 @@ +/* XPM */ +static char * dropper_xpm[] = { +"22 22 3 1", +" c None", +". c #FFFFFF", +"+ c #000000", +" ", +" ", +" ", +" ... ", +" ..... ", +" .+.... ", +" .++++.... ", +" .+++.++. ", +" ...+..+. ", +" .+...+. ", +" ..++..+. ", +" . .++..+. ", +" .++..+. ", +" .++..+. ", +" .++..+. ", +" .++..+. ", +" .++..+. ", +" .++..+. ", +" .++.+. ", +" .++++. ", +" ... ", +" . "};