1 /* run the display for an image in a workspace
2 */
3
4 /*
5
6 Copyright (C) 1991-2003 The National Gallery
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License along
19 with this program; if not, write to the Free Software Foundation, Inc.,
20 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
22 */
23
24 /*
25
26 These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
27
28 */
29
30 /*
31 #define DEBUG
32 */
33
34 #include "ip.h"
35
36 static GraphicviewClass *parent_class = NULL;
37
38 static void
iimageview_realize(GtkWidget * widget)39 iimageview_realize( GtkWidget *widget )
40 {
41 GTK_WIDGET_CLASS( parent_class )->realize( widget );
42
43 /* Mark us as a symbol drag-to widget.
44 */
45 set_symbol_drag_type( widget );
46 }
47
48 GtkWidget *
iimageview_drag_window_new(int width,int height)49 iimageview_drag_window_new( int width, int height )
50 {
51 GtkWidget *window;
52
53 window = gtk_window_new( GTK_WINDOW_POPUP );
54 gtk_widget_set_app_paintable( GTK_WIDGET( window ), TRUE );
55 gtk_widget_set_size_request( window, width, height );
56 gtk_widget_realize( window );
57 #ifdef HAVE_SET_OPACITY
58 gdk_window_set_opacity( window->window, 0.5 );
59 #endif /*HAVE_SET_OPACITY*/
60
61 return( window );
62 }
63
64 static void
iimageview_drag_begin(GtkWidget * widget,GdkDragContext * context)65 iimageview_drag_begin( GtkWidget *widget, GdkDragContext *context )
66 {
67 iImageview *iimageview = IIMAGEVIEW( widget );
68 Conversion *conv = iimageview->conv;
69 GtkWidget *window;
70 Imagedisplay *id;
71
72 #ifdef DEBUG
73 printf( "iimageview_drag_begin: \n" );
74 #endif /*DEBUG*/
75
76 window = iimageview_drag_window_new(
77 conv->canvas.width, conv->canvas.height );
78 gtk_object_set_data_full( GTK_OBJECT( widget ),
79 "nip2-drag-window", window,
80 (GtkDestroyNotify) gtk_widget_destroy );
81 id = imagedisplay_new( conv );
82 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( id ) );
83 gtk_widget_show( GTK_WIDGET( id ) );
84 gtk_drag_set_icon_widget( context, window, -2, -2 );
85 }
86
87 static void
iimageview_drag_end(GtkWidget * widget,GdkDragContext * context)88 iimageview_drag_end( GtkWidget *widget, GdkDragContext *context )
89 {
90 #ifdef DEBUG
91 printf( "iimageview_drag_end:\n" );
92 #endif /*DEBUG*/
93
94 gtk_object_set_data( GTK_OBJECT( widget ),
95 "nip2-drag-window", NULL );
96 }
97
98 static void
iimageview_drag_data_get(GtkWidget * widget,GdkDragContext * context,GtkSelectionData * selection_data,guint info,guint time)99 iimageview_drag_data_get( GtkWidget *widget, GdkDragContext *context,
100 GtkSelectionData *selection_data, guint info, guint time )
101 {
102 #ifdef DEBUG
103 printf( "iimageview_drag_data_get:\n" );
104 #endif /*DEBUG*/
105
106 if( info == TARGET_SYMBOL ) {
107 iImageview *iimageview = IIMAGEVIEW( widget );
108 iImage *iimage = IIMAGE( VOBJECT( iimageview )->iobject );
109 Row *row = HEAPMODEL( iimage )->row;
110 char txt[256];
111 VipsBuf buf = VIPS_BUF_STATIC( txt );
112
113 /* Drag the fully-qualified row name.
114 */
115 row_qualified_name_relative( main_workspaceroot->sym,
116 row, &buf );
117 gtk_selection_data_set( selection_data,
118 gdk_atom_intern( "text/symbol", FALSE ), 8,
119 (guchar *) vips_buf_all( &buf ),
120 strlen( vips_buf_all( &buf ) ) );
121 }
122 }
123
124 static void
iimageview_drag_data_received(GtkWidget * widget,GdkDragContext * context,gint x,gint y,GtkSelectionData * selection_data,guint info,guint time)125 iimageview_drag_data_received( GtkWidget *widget, GdkDragContext *context,
126 gint x, gint y, GtkSelectionData *selection_data,
127 guint info, guint time )
128 {
129
130 #ifdef DEBUG
131 printf( "iimageview_drag_data_received:\n" );
132 #endif /*DEBUG*/
133
134 if( info == TARGET_SYMBOL && selection_data->length > 0 &&
135 selection_data->format == 8 ) {
136 const char *from_row_path = (const char *) selection_data->data;
137 iImageview *iimageview = IIMAGEVIEW( widget );
138 iImage *iimage = IIMAGE( VOBJECT( iimageview )->iobject );
139 Row *row = HEAPMODEL( iimage )->row;
140 Row *from_row;
141
142 #ifdef DEBUG
143 printf( " seen TARGET_SYMBOL \"%s\"\n",
144 from_row_path );
145 #endif /*DEBUG*/
146
147 /* Block drags to ourselves ... pointless.
148 */
149 if( (from_row = row_parse_name( main_workspaceroot->sym,
150 from_row_path )) &&
151 from_row != row ) {
152 iText *itext = ITEXT( HEAPMODEL( iimage )->rhs->itext );
153 char txt[256];
154 VipsBuf buf = VIPS_BUF_STATIC( txt );
155
156 /* Qualify relative to us. We don't want to embed
157 * workspace names unless we have to.
158 */
159 if( row->top_row->sym )
160 row_qualified_name_relative( row->top_row->sym,
161 from_row, &buf );
162
163 if( itext_set_formula( itext, vips_buf_all( &buf ) ) ) {
164 itext_set_edited( itext, TRUE );
165 (void) expr_dirty( row->expr,
166 link_serial_new() );
167 workspace_set_modified( row->ws, TRUE );
168 symbol_recalculate_all();
169 }
170
171 /* Usually the drag-from row will be selected, very
172 * annoying. Select the drag-to row.
173 */
174 row_select( row );
175 }
176 }
177 }
178
179 /* Not the same as model->edit :-( if this is a region, don't pop the region
180 * edit box, pop a viewer on the image.
181 */
182 static void
iimageview_edit(GtkWidget * parent,iImageview * iimageview)183 iimageview_edit( GtkWidget *parent, iImageview *iimageview )
184 {
185 iImage *iimage = IIMAGE( VOBJECT( iimageview )->iobject );
186
187 if( IS_IREGION( iimage ) && iimage->value.ii )
188 imageview_new( iimage, parent );
189 else
190 model_edit( parent, MODEL( iimage ) );
191 }
192
193 static void
iimageview_link(View * view,Model * model,View * parent)194 iimageview_link( View *view, Model *model, View *parent )
195 {
196 iImageview *iimageview = IIMAGEVIEW( view );
197
198 Rowview *rview;
199
200 VIEW_CLASS( parent_class )->link( view, model, parent );
201
202 if( (rview = ROWVIEW( parent->parent )) ) {
203 Row *row = ROW( VOBJECT( rview )->iobject );
204
205 rowview_menu_attach( rview, GTK_WIDGET( iimageview->id ) );
206
207 if( row->popup && row->top_row == row ) {
208 row->popup = FALSE;
209 iimageview_edit( GTK_WIDGET( view ), iimageview );
210 }
211 }
212 }
213
214 static void
iimageview_refresh(vObject * vobject)215 iimageview_refresh( vObject *vobject )
216 {
217 iImageview *iimageview = IIMAGEVIEW( vobject );
218 iImage *iimage = IIMAGE( vobject->iobject );
219 Row *row = HEAPMODEL( iimage )->row;
220
221 int w, h;
222 gboolean enabled;
223 double scale, offset;
224 gboolean falsecolour, type;
225
226 #ifdef DEBUG
227 printf( "iimageview_refresh\n" );
228 #endif /*DEBUG*/
229
230 w = IM_MAX( GTK_WIDGET( iimageview->id )->requisition.width,
231 DISPLAY_THUMBNAIL );
232 h = DISPLAY_THUMBNAIL;
233 conversion_set_image( iimageview->conv, iimage->value.ii );
234 gtk_widget_set_size_request( GTK_WIDGET( iimageview->id ), w, h );
235 gtk_widget_queue_draw( GTK_WIDGET( iimageview->id ) );
236
237 set_gcaption( iimageview->label, "%s",
238 NN( IOBJECT( iimage )->caption ) );
239
240 /* Set scale/offset for the thumbnail. Use the prefs setting, or if
241 * there's a setting for this image, override with that.
242 */
243 enabled = DISPLAY_CONVERSION;
244 scale = row->ws->scale;
245 offset = row->ws->offset;
246 falsecolour = FALSE;
247 type = TRUE;
248
249 /* If the image_width has been set, a viewer must have popped down and
250 * set it, so the recorded settings must be valid.
251 */
252 if( MODEL( iimage )->window_width != -1 ) {
253 enabled = iimage->show_convert;
254 scale = iimage->scale;
255 offset = iimage->offset;
256 falsecolour = iimage->falsecolour;
257 type = iimage->type;
258 }
259
260 conversion_set_params( iimageview->conv,
261 enabled, scale, offset, falsecolour, type );
262
263 VOBJECT_CLASS( parent_class )->refresh( vobject );
264 }
265
266 static void
iimageview_class_init(iImageviewClass * class)267 iimageview_class_init( iImageviewClass *class )
268 {
269 GtkWidgetClass *widget_class = (GtkWidgetClass *) class;
270 vObjectClass *vobject_class = (vObjectClass *) class;
271 ViewClass *view_class = (ViewClass *) class;
272
273 parent_class = g_type_class_peek_parent( class );
274
275 /* Create signals.
276 */
277
278 /* Init methods.
279 */
280 widget_class->realize = iimageview_realize;
281 widget_class->drag_begin = iimageview_drag_begin;
282 widget_class->drag_end = iimageview_drag_end;
283 widget_class->drag_data_get = iimageview_drag_data_get;
284 widget_class->drag_data_received = iimageview_drag_data_received;
285
286 vobject_class->refresh = iimageview_refresh;
287
288 view_class->link = iimageview_link;
289 }
290
291 static void
iimageview_doubleclick_one_cb(GtkWidget * widget,GdkEvent * event,iImageview * iimageview)292 iimageview_doubleclick_one_cb( GtkWidget *widget, GdkEvent *event,
293 iImageview *iimageview )
294 {
295 Heapmodel *heapmodel = HEAPMODEL( VOBJECT( iimageview )->iobject );
296 Row *row = heapmodel->row;
297
298 row_select_modifier( row, event->button.state );
299 }
300
301 static void
iimageview_doubleclick_two_cb(GtkWidget * widget,GdkEvent * event,iImageview * iimageview)302 iimageview_doubleclick_two_cb( GtkWidget *widget, GdkEvent *event,
303 iImageview *iimageview )
304 {
305 iimageview_edit( widget, iimageview );
306 }
307
308 static gboolean
iimageview_filedrop(iImageview * iimageview,const char * file)309 iimageview_filedrop( iImageview *iimageview, const char *file )
310 {
311 iImage *iimage = IIMAGE( VOBJECT( iimageview )->iobject );
312 gboolean result;
313
314 if( (result = iimage_replace( iimage, file )) )
315 symbol_recalculate_all();
316
317 return( result );
318 }
319
320 static void
iimageview_tooltip_generate(GtkWidget * widget,VipsBuf * buf,iImageview * iimageview)321 iimageview_tooltip_generate( GtkWidget *widget,
322 VipsBuf *buf, iImageview *iimageview )
323 {
324 iImage *iimage = IIMAGE( VOBJECT( iimageview )->iobject );
325 Imageinfo *ii = iimage->value.ii;
326 IMAGE *im = imageinfo_get( FALSE, ii );
327
328 vips_buf_rewind( buf );
329 vips_buf_appends( buf, vips_buf_all( &iimage->caption_buffer ) );
330 if( im ) {
331 double size = (double) im->Ysize * IM_IMAGE_SIZEOF_LINE( im );
332
333 vips_buf_appends( buf, ", " );
334 vips_buf_append_size( buf, size );
335 vips_buf_appendf( buf, ", %.3gx%.3g p/mm", im->Xres, im->Yres );
336 }
337 }
338
339 static void
iimageview_init(iImageview * iimageview)340 iimageview_init( iImageview *iimageview )
341 {
342 GtkWidget *eb;
343 GtkWidget *vbox;
344
345 #ifdef DEBUG
346 printf( "iimageview_init\n" );
347 #endif /*DEBUG*/
348
349 eb = gtk_event_box_new();
350 gtk_box_pack_start( GTK_BOX( iimageview ), eb, FALSE, FALSE, 0 );
351 vbox = gtk_vbox_new( FALSE, 0 );
352 gtk_container_add( GTK_CONTAINER( eb ), vbox );
353 gtk_widget_show( vbox );
354
355 iimageview->conv = conversion_new( NULL );
356 iimageview->conv->tile_size = 16;
357 iimageview->id = imagedisplay_new( iimageview->conv );
358 imagedisplay_set_shrink_to_fit( iimageview->id, TRUE );
359 gtk_box_pack_start( GTK_BOX( vbox ),
360 GTK_WIDGET( iimageview->id ), FALSE, FALSE, 0 );
361 gtk_widget_show( GTK_WIDGET( iimageview->id ) );
362
363 /* Need these events in the enclosing workspaceview.
364 */
365 gtk_widget_add_events( GTK_WIDGET( iimageview->id ),
366 GDK_POINTER_MOTION_MASK |
367 GDK_POINTER_MOTION_HINT_MASK |
368 GDK_BUTTON_PRESS_MASK |
369 GDK_BUTTON_RELEASE_MASK );
370
371 iimageview->label = gtk_label_new( "" );
372 gtk_misc_set_alignment( GTK_MISC( iimageview->label ), 0, 0.5 );
373 gtk_misc_set_padding( GTK_MISC( iimageview->label ), 2, 0 );
374 gtk_box_pack_start( GTK_BOX( vbox ),
375 GTK_WIDGET( iimageview->label ), FALSE, FALSE, 0 );
376 gtk_widget_show( GTK_WIDGET( iimageview->label ) );
377
378 /* Set as file drop destination
379 */
380 filedrop_register( GTK_WIDGET( iimageview ),
381 (FiledropFunc) iimageview_filedrop, iimageview );
382
383 doubleclick_add( GTK_WIDGET( iimageview ), FALSE,
384 DOUBLECLICK_FUNC( iimageview_doubleclick_one_cb ), iimageview,
385 DOUBLECLICK_FUNC( iimageview_doubleclick_two_cb ), iimageview );
386
387 set_tooltip_generate( eb,
388 (TooltipGenerateFn) iimageview_tooltip_generate,
389 iimageview, NULL );
390
391 gtk_widget_set_name( eb, "caption_widget" );
392 gtk_widget_show( GTK_WIDGET( eb ) );
393 }
394
395 GtkType
iimageview_get_type(void)396 iimageview_get_type( void )
397 {
398 static GtkType iimageview_type = 0;
399
400 if( !iimageview_type ) {
401 static const GtkTypeInfo info = {
402 "iImageview",
403 sizeof( iImageview ),
404 sizeof( iImageviewClass ),
405 (GtkClassInitFunc) iimageview_class_init,
406 (GtkObjectInitFunc) iimageview_init,
407 /* reserved_1 */ NULL,
408 /* reserved_2 */ NULL,
409 (GtkClassInitFunc) NULL,
410 };
411
412 iimageview_type = gtk_type_unique( TYPE_GRAPHICVIEW, &info );
413 }
414
415 return( iimageview_type );
416 }
417
418 View *
iimageview_new(void)419 iimageview_new( void )
420 {
421 iImageview *iimageview = gtk_type_new( TYPE_IIMAGEVIEW );
422
423 return( VIEW( iimageview ) );
424 }
425