gimpimagedock.c 14.9 KB
Newer Older
Michael Natterer's avatar
Michael Natterer committed
1
2
3
4
/* The GIMP -- an image manipulation program
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * gimpimagedock.c
5
 * Copyright (C) 2001 Michael Natterer <mitch@gimp.org>
Michael Natterer's avatar
Michael Natterer committed
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include "config.h"

#include <gtk/gtk.h>

#include "libgimpwidgets/gimpwidgets.h"

28
#include "widgets-types.h"
Michael Natterer's avatar
Michael Natterer committed
29

30
#include "core/gimp.h"
31
32
#include "core/gimpcontext.h"
#include "core/gimpimage.h"
33
34
35
36
37
#include "core/gimplist.h"

#warning FIXME #include "display/display-types.h"
#include "display/display-types.h"
#include "display/gimpdisplay.h"
38

Michael Natterer's avatar
Michael Natterer committed
39
40
41
#include "gimpdialogfactory.h"
#include "gimpimagedock.h"
#include "gimpcontainermenuimpl.h"
42
#include "gimpdnd.h"
Michael Natterer's avatar
Michael Natterer committed
43
#include "gimpdockbook.h"
44
45
#include "gimpmenuitem.h"
#include "gimppreview.h"
Michael Natterer's avatar
Michael Natterer committed
46

Michael Natterer's avatar
Michael Natterer committed
47
#include "libgimp/gimpintl.h"
Michael Natterer's avatar
Michael Natterer committed
48
49


50
51
#define DEFAULT_MINIMAL_WIDTH     250
#define DEFAULT_MENU_PREVIEW_SIZE GTK_ICON_SIZE_SMALL_TOOLBAR
52
53


Michael Natterer's avatar
Michael Natterer committed
54
55
static void   gimp_image_dock_class_init       (GimpImageDockClass *klass);
static void   gimp_image_dock_init             (GimpImageDock      *dock);
Michael Natterer's avatar
Michael Natterer committed
56

Michael Natterer's avatar
Michael Natterer committed
57
static void   gimp_image_dock_destroy                 (GtkObject   *object);
Michael Natterer's avatar
Michael Natterer committed
58

Michael Natterer's avatar
Michael Natterer committed
59
60
static void   gimp_image_dock_style_set               (GtkWidget   *widget,
                                                       GtkStyle    *prev_style);
61

Michael Natterer's avatar
Michael Natterer committed
62
63
64
65
66
67
68
69
70
71
72
static void   gimp_image_dock_factory_display_changed (GimpContext *context,
                                                       GimpObject  *gdisp,
                                                       GimpDock    *dock);
static void   gimp_image_dock_factory_image_changed   (GimpContext *context,
                                                       GimpImage   *gimage,
                                                       GimpDock    *dock);
static void   gimp_image_dock_image_changed           (GimpContext *context,
                                                       GimpImage   *gimage,
                                                       GimpDock    *dock);
static void   gimp_image_dock_auto_clicked            (GtkWidget   *widget,
                                                       GimpDock    *dock);
Michael Natterer's avatar
Michael Natterer committed
73
74
75
76
77


static GimpDockClass *parent_class = NULL;


78
GType
Michael Natterer's avatar
Michael Natterer committed
79
80
gimp_image_dock_get_type (void)
{
81
  static GType dock_type = 0;
Michael Natterer's avatar
Michael Natterer committed
82
83
84

  if (! dock_type)
    {
85
      static const GTypeInfo dock_info =
Michael Natterer's avatar
Michael Natterer committed
86
      {
87
88
89
90
91
92
93
94
95
        sizeof (GimpImageDockClass),
        NULL,           /* base_init */
        NULL,           /* base_finalize */
        (GClassInitFunc) gimp_image_dock_class_init,
        NULL,           /* class_finalize */
        NULL,           /* class_data */
        sizeof (GimpImageDock),
        0,              /* n_preallocs */
        (GInstanceInitFunc) gimp_image_dock_init,
Michael Natterer's avatar
Michael Natterer committed
96
97
      };

98
99
100
      dock_type = g_type_register_static (GIMP_TYPE_DOCK,
                                          "GimpImageDock",
                                          &dock_info, 0);
Michael Natterer's avatar
Michael Natterer committed
101
102
103
104
105
106
107
108
109
    }

  return dock_type;
}

static void
gimp_image_dock_class_init (GimpImageDockClass *klass)
{
  GtkObjectClass *object_class;
110
  GtkWidgetClass *widget_class;
Michael Natterer's avatar
Michael Natterer committed
111

112
  object_class = GTK_OBJECT_CLASS (klass);
113
  widget_class = GTK_WIDGET_CLASS (klass);
Michael Natterer's avatar
Michael Natterer committed
114

115
  parent_class = g_type_class_peek_parent (klass);
Michael Natterer's avatar
Michael Natterer committed
116

117
118
119
120
121
122
123
124
125
126
127
  object_class->destroy   = gimp_image_dock_destroy;

  widget_class->style_set = gimp_image_dock_style_set;

  gtk_widget_class_install_style_property (widget_class,
                                           g_param_spec_int ("minimal_width",
                                                             NULL, NULL,
                                                             0,
                                                             G_MAXINT,
                                                             DEFAULT_MINIMAL_WIDTH,
                                                             G_PARAM_READABLE));
128
  gtk_widget_class_install_style_property (widget_class,
129
130
131
132
133
                                           g_param_spec_enum ("menu_preview_size",
                                                              NULL, NULL,
                                                              GTK_TYPE_ICON_SIZE,
                                                              DEFAULT_MENU_PREVIEW_SIZE,
                                                              G_PARAM_READABLE));
Michael Natterer's avatar
Michael Natterer committed
134
135
136
137
138
}

static void
gimp_image_dock_init (GimpImageDock *dock)
{
Michael Natterer's avatar
Michael Natterer committed
139
140
141
  GtkWidget *hbox;

  dock->image_container    = NULL;
142
  dock->display_container  = NULL;
143
  dock->show_image_menu    = FALSE;
Michael Natterer's avatar
Michael Natterer committed
144
145
146
147
  dock->auto_follow_active = TRUE;

  hbox = gtk_hbox_new (FALSE, 2);
  gtk_box_pack_start (GTK_BOX (GIMP_DOCK (dock)->main_vbox), hbox,
Michael Natterer's avatar
Michael Natterer committed
148
                      FALSE, FALSE, 0);
Michael Natterer's avatar
Michael Natterer committed
149
  gtk_box_reorder_child (GTK_BOX (GIMP_DOCK (dock)->main_vbox), hbox, 0);
150
151
152

  if (dock->show_image_menu)
    gtk_widget_show (hbox);
Michael Natterer's avatar
Michael Natterer committed
153
154
155

  dock->option_menu = gtk_option_menu_new ();
  gtk_box_pack_start (GTK_BOX (hbox), dock->option_menu, TRUE, TRUE, 0);
Michael Natterer's avatar
Michael Natterer committed
156
157
  gtk_widget_show (dock->option_menu);

158
159
160
161
  g_signal_connect (G_OBJECT (dock->option_menu), "destroy",
		    G_CALLBACK (gtk_widget_destroyed),
		    &dock->option_menu);

162
163
  dock->auto_button = gtk_toggle_button_new_with_label (_("Auto"));
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dock->auto_button),
Michael Natterer's avatar
Michael Natterer committed
164
				dock->auto_follow_active);
165
166
  gtk_box_pack_start (GTK_BOX (hbox), dock->auto_button, FALSE, FALSE, 0);
  gtk_widget_show (dock->auto_button);
Michael Natterer's avatar
Michael Natterer committed
167

168
169
170
  g_signal_connect (G_OBJECT (dock->auto_button), "clicked",
		    G_CALLBACK (gimp_image_dock_auto_clicked),
		    dock);
Michael Natterer's avatar
Michael Natterer committed
171
172
173
174
175
176
177
178
179
}

static void
gimp_image_dock_destroy (GtkObject *object)
{
  GimpImageDock *dock;

  dock = GIMP_IMAGE_DOCK (object);

Michael Natterer's avatar
Michael Natterer committed
180
181
182
  /*  remove the image menu and the auto button manually here because
   *  of weird cross-connections with GimpDock's context
   */
183
184
185
186
187
188
189
  if (GIMP_DOCK (dock)->main_vbox &&
      dock->option_menu           &&
      dock->option_menu->parent)
    {
      gtk_container_remove (GTK_CONTAINER (GIMP_DOCK (dock)->main_vbox),
			    dock->option_menu->parent);
    }
Michael Natterer's avatar
Michael Natterer committed
190

Michael Natterer's avatar
Michael Natterer committed
191
192
193
194
  if (GTK_OBJECT_CLASS (parent_class))
    GTK_OBJECT_CLASS (parent_class)->destroy (object);
}

195
196
197
198
static void
gimp_image_dock_style_set (GtkWidget *widget,
                           GtkStyle  *prev_style)
{
199
200
  GimpImageDock *image_dock;
  gint           minimal_width;
201
202
203
  GtkIconSize    menu_preview_size;
  gint           menu_preview_width  = 18;
  gint           menu_preview_height = 18;
204
205
206
207
208
  gint           focus_line_width;
  gint           focus_padding;
  gint           ythickness;

  image_dock = GIMP_IMAGE_DOCK (widget);
209
210
211
212
213

  if (GTK_WIDGET_CLASS (parent_class)->style_set)
    GTK_WIDGET_CLASS (parent_class)->style_set (widget, prev_style);

  gtk_widget_style_get (widget,
214
215
                        "minimal_width",     &minimal_width,
                        "menu_preview_size", &menu_preview_size,
216
217
			NULL);

218
219
220
221
  gtk_icon_size_lookup (menu_preview_size,
                        &menu_preview_width,
                        &menu_preview_height);

222
223
224
225
226
227
228
  gtk_widget_style_get (image_dock->auto_button,
                        "focus_line_width", &focus_line_width,
                        "focus_padding",    &focus_padding,
			NULL);

  ythickness = image_dock->auto_button->style->ythickness;

229
  gtk_widget_set_size_request (widget, minimal_width, -1);
230
231
232
233
234
235
236
237
238
239

  gimp_container_menu_set_preview_size (GIMP_CONTAINER_MENU (image_dock->menu),
                                        menu_preview_height);

  gtk_widget_set_size_request (image_dock->auto_button, -1,
                               menu_preview_height +
                               2 * (1 /* CHILD_SPACING */ +
                                    ythickness            +
                                    focus_padding         +
                                    focus_line_width));
240
241
}

Michael Natterer's avatar
Michael Natterer committed
242
GtkWidget *
243
gimp_image_dock_new (GimpDialogFactory *dialog_factory,
244
245
		     GimpContainer     *image_container,
                     GimpContainer     *display_container)
Michael Natterer's avatar
Michael Natterer committed
246
247
{
  GimpImageDock *image_dock;
248
  GimpContext   *context;
249
  gchar         *title;
250
251
  gint           menu_preview_width;
  gint           menu_preview_height;
252
253

  static gint dock_counter = 1;
Michael Natterer's avatar
Michael Natterer committed
254

255
  g_return_val_if_fail (GIMP_IS_DIALOG_FACTORY (dialog_factory), NULL);
Michael Natterer's avatar
Michael Natterer committed
256
  g_return_val_if_fail (GIMP_IS_CONTAINER (image_container), NULL);
257
  g_return_val_if_fail (GIMP_IS_CONTAINER (display_container), NULL);
Michael Natterer's avatar
Michael Natterer committed
258

Michael Natterer's avatar
Michael Natterer committed
259
  image_dock = g_object_new (GIMP_TYPE_IMAGE_DOCK, NULL);
Michael Natterer's avatar
Michael Natterer committed
260

261
262
263
264
  title = g_strdup_printf (_("Gimp Dock #%d"), dock_counter++);
  gtk_window_set_title (GTK_WINDOW (image_dock), title);
  g_free (title);

265
266
  image_dock->image_container   = image_container;
  image_dock->display_container = display_container;
Michael Natterer's avatar
Michael Natterer committed
267

268
269
270
271
  context = gimp_context_new (dialog_factory->context->gimp,
                              "Dock Context", NULL);

  gimp_dock_construct (GIMP_DOCK (image_dock), dialog_factory, context, TRUE);
Michael Natterer's avatar
Michael Natterer committed
272

273
  gimp_context_define_properties (context,
274
275
276
277
				  GIMP_CONTEXT_ALL_PROPS_MASK &
				  ~(GIMP_CONTEXT_IMAGE_MASK |
				    GIMP_CONTEXT_DISPLAY_MASK),
				  FALSE);
278
  gimp_context_set_parent (context, dialog_factory->context);
Michael Natterer's avatar
Michael Natterer committed
279

280
  if (image_dock->auto_follow_active)
281
282
283
284
285
286
287
288
    {
      if (gimp_context_get_display (dialog_factory->context))
        gimp_context_copy_property (dialog_factory->context, context,
                                    GIMP_CONTEXT_PROP_DISPLAY);
      else
        gimp_context_copy_property (dialog_factory->context, context,
                                    GIMP_CONTEXT_PROP_IMAGE);
    }
289

Michael Natterer's avatar
Michael Natterer committed
290
291
292
293
  g_signal_connect_object (G_OBJECT (dialog_factory->context), "display_changed",
			   G_CALLBACK (gimp_image_dock_factory_display_changed),
			   G_OBJECT (image_dock),
			   0);
294
  g_signal_connect_object (G_OBJECT (dialog_factory->context), "image_changed",
295
			   G_CALLBACK (gimp_image_dock_factory_image_changed),
296
			   G_OBJECT (image_dock),
297
			   0);
Michael Natterer's avatar
Michael Natterer committed
298

299
  g_signal_connect_object (G_OBJECT (context), "image_changed",
300
			   G_CALLBACK (gimp_image_dock_image_changed),
301
			   G_OBJECT (image_dock),
302
			   0);
Michael Natterer's avatar
Michael Natterer committed
303

304
305
306
  gtk_icon_size_lookup (DEFAULT_MENU_PREVIEW_SIZE,
                        &menu_preview_width, &menu_preview_height);

307
  image_dock->menu = gimp_container_menu_new (image_container, context,
308
                                              menu_preview_height);
Michael Natterer's avatar
Michael Natterer committed
309
310
311
312
  gtk_option_menu_set_menu (GTK_OPTION_MENU (image_dock->option_menu),
			    image_dock->menu);
  gtk_widget_show (image_dock->menu);

313
314
  g_object_unref (G_OBJECT (context));

Michael Natterer's avatar
Michael Natterer committed
315
316
  return GTK_WIDGET (image_dock);
}
Michael Natterer's avatar
Michael Natterer committed
317

318
319
320
321
322
323
324
325
326
327
void
gimp_image_dock_set_auto_follow_active (GimpImageDock *image_dock,
					gboolean       auto_follow_active)
{
  g_return_if_fail (GIMP_IS_IMAGE_DOCK (image_dock));

  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (image_dock->auto_button),
				auto_follow_active ? TRUE : FALSE);
}

Michael Natterer's avatar
Michael Natterer committed
328
329
330
331
332
333
334
void
gimp_image_dock_set_show_image_menu (GimpImageDock *image_dock,
				     gboolean       show)
{
  g_return_if_fail (GIMP_IS_IMAGE_DOCK (image_dock));

  if (show)
335
    gtk_widget_show (image_dock->option_menu->parent);
Michael Natterer's avatar
Michael Natterer committed
336
  else
337
    gtk_widget_hide (image_dock->option_menu->parent);
338
339

  image_dock->show_image_menu = show ? TRUE : FALSE;
Michael Natterer's avatar
Michael Natterer committed
340
341
}

Michael Natterer's avatar
Michael Natterer committed
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
static void
gimp_image_dock_factory_display_changed (GimpContext *context,
                                         GimpObject  *gdisp,
                                         GimpDock    *dock)
{
  GimpImageDock *image_dock;

  image_dock = GIMP_IMAGE_DOCK (dock);

  if (gdisp && image_dock->auto_follow_active)
    {
      gimp_context_set_display (dock->context, gdisp);
    }
}

Michael Natterer's avatar
Michael Natterer committed
357
358
359
360
361
362
363
364
365
366
367
static void
gimp_image_dock_factory_image_changed (GimpContext *context,
				       GimpImage   *gimage,
				       GimpDock    *dock)
{
  GimpImageDock *image_dock;

  image_dock = GIMP_IMAGE_DOCK (dock);

  if (gimage && image_dock->auto_follow_active)
    {
Michael Natterer's avatar
Michael Natterer committed
368
369
      /*  won't do anything if we already set the display above
       */
Michael Natterer's avatar
Michael Natterer committed
370
371
372
373
374
375
376
377
378
379
380
381
382
      gimp_context_set_image (dock->context, gimage);
    }
}

static void
gimp_image_dock_image_changed (GimpContext *context,
			       GimpImage   *gimage,
			       GimpDock    *dock)
{
  GimpImageDock *image_dock;

  image_dock = GIMP_IMAGE_DOCK (dock);

383
  if (! gimage && image_dock->image_container->num_children > 0)
Michael Natterer's avatar
Michael Natterer committed
384
385
386
    {
      gimage = GIMP_IMAGE (gimp_container_get_child_by_index (image_dock->image_container, 0));

387
388
389
390
391
      if (gimage)
	{
	  /*  this invokes this function recursively but we don't enter
	   *  the if() branch the second time
	   */
392
	  gimp_context_set_image (context, gimage);
393
394
395
396

	  /*  stop the emission of the original signal (the emission of
	   *  the recursive signal is finished)
	   */
397
	  g_signal_stop_emission_by_name (G_OBJECT (context), "image_changed");
398
	}
Michael Natterer's avatar
Michael Natterer committed
399
    }
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
  else if (image_dock->display_container->num_children > 0)
    {
      GimpObject *gdisp;
      gboolean    find_display = TRUE;

      gdisp = gimp_context_get_display (context);

      if (gdisp)
        {
          GimpImage *gdisp_gimage;

          g_object_get (gdisp, "image", &gdisp_gimage, NULL);
          g_object_unref (G_OBJECT (gdisp_gimage));

          if (gdisp_gimage == gimage)
            find_display = FALSE;
        }

      if (find_display)
        {
          GList *list;

          for (list = GIMP_LIST (image_dock->display_container)->list;
               list;
               list = g_list_next (list))
            {
              GimpImage *gdisp_gimage;

              gdisp = GIMP_OBJECT (list->data);

              g_object_get (gdisp, "image", &gdisp_gimage, NULL);
              g_object_unref (G_OBJECT (gdisp_gimage));

              if (gdisp_gimage == gimage)
                {
                  /*  this invokes this function recursively but we don't enter
                   *  the if(find_display) branch the second time
                   */
                  gimp_context_set_display (context, gdisp);

                  /*  don't stop signal emission here because the context's
                   *  image was not changed by the recursive call
                   */
                  break;
                }
            }
        }
    }
Michael Natterer's avatar
Michael Natterer committed
448
449
450
451
452
453
454
455
456
457
458
459
460
461
}

static void
gimp_image_dock_auto_clicked (GtkWidget *widget,
			      GimpDock  *dock)
{
  GimpImageDock *image_dock;

  image_dock = GIMP_IMAGE_DOCK (dock);

  gimp_toggle_button_update (widget, &image_dock->auto_follow_active);

  if (image_dock->auto_follow_active)
    {
462
463
464
      if (gimp_context_get_display (dock->dialog_factory->context))
        gimp_context_copy_property (dock->dialog_factory->context, dock->context,
                                    GIMP_CONTEXT_PROP_DISPLAY);
Michael Natterer's avatar
Michael Natterer committed
465
      else
466
467
        gimp_context_copy_property (dock->dialog_factory->context, dock->context,
                                    GIMP_CONTEXT_PROP_IMAGE);
Michael Natterer's avatar
Michael Natterer committed
468
469
    }
}