gimpimagedock.c 14.5 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_HEIGHT  24
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
129
130
131
132
133
134
  gtk_widget_class_install_style_property (widget_class,
                                           g_param_spec_int ("menu_preview_height",
                                                             NULL, NULL,
                                                             0,
                                                             G_MAXINT,
                                                             DEFAULT_MENU_PREVIEW_HEIGHT,
                                                             G_PARAM_READABLE));
Michael Natterer's avatar
Michael Natterer committed
135
136
137
138
139
}

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

  dock->image_container    = NULL;
143
  dock->display_container  = NULL;
144
  dock->show_image_menu    = FALSE;
Michael Natterer's avatar
Michael Natterer committed
145
146
147
148
  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
149
                      FALSE, FALSE, 0);
Michael Natterer's avatar
Michael Natterer committed
150
  gtk_box_reorder_child (GTK_BOX (GIMP_DOCK (dock)->main_vbox), hbox, 0);
151
152
153

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

  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
157
158
  gtk_widget_show (dock->option_menu);

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

163
164
  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
165
				dock->auto_follow_active);
166
167
  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
168

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

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

  dock = GIMP_IMAGE_DOCK (object);

Michael Natterer's avatar
Michael Natterer committed
181
182
183
  /*  remove the image menu and the auto button manually here because
   *  of weird cross-connections with GimpDock's context
   */
184
185
186
187
188
189
190
  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
191

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

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

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

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

  gtk_widget_style_get (widget,
213
214
                        "minimal_width",       &minimal_width,
                        "menu_preview_height", &menu_preview_height,
215
216
			NULL);

217
218
219
220
221
222
223
  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;

224
  gtk_widget_set_size_request (widget, minimal_width, -1);
225
226
227
228
229
230
231
232
233
234

  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));
235
236
}

Michael Natterer's avatar
Michael Natterer committed
237
GtkWidget *
238
gimp_image_dock_new (GimpDialogFactory *dialog_factory,
239
240
		     GimpContainer     *image_container,
                     GimpContainer     *display_container)
Michael Natterer's avatar
Michael Natterer committed
241
242
{
  GimpImageDock *image_dock;
243
  GimpContext   *context;
244
245
246
  gchar         *title;

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

248
  g_return_val_if_fail (GIMP_IS_DIALOG_FACTORY (dialog_factory), NULL);
Michael Natterer's avatar
Michael Natterer committed
249
  g_return_val_if_fail (GIMP_IS_CONTAINER (image_container), NULL);
250
  g_return_val_if_fail (GIMP_IS_CONTAINER (display_container), NULL);
Michael Natterer's avatar
Michael Natterer committed
251

Michael Natterer's avatar
Michael Natterer committed
252
  image_dock = g_object_new (GIMP_TYPE_IMAGE_DOCK, NULL);
Michael Natterer's avatar
Michael Natterer committed
253

254
255
256
257
  title = g_strdup_printf (_("Gimp Dock #%d"), dock_counter++);
  gtk_window_set_title (GTK_WINDOW (image_dock), title);
  g_free (title);

258
259
  image_dock->image_container   = image_container;
  image_dock->display_container = display_container;
Michael Natterer's avatar
Michael Natterer committed
260

261
262
263
264
  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
265

266
  gimp_context_define_properties (context,
267
268
269
270
				  GIMP_CONTEXT_ALL_PROPS_MASK &
				  ~(GIMP_CONTEXT_IMAGE_MASK |
				    GIMP_CONTEXT_DISPLAY_MASK),
				  FALSE);
271
  gimp_context_set_parent (context, dialog_factory->context);
Michael Natterer's avatar
Michael Natterer committed
272

273
  if (image_dock->auto_follow_active)
274
275
276
277
278
279
280
281
    {
      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);
    }
282

Michael Natterer's avatar
Michael Natterer committed
283
284
285
286
  g_signal_connect_object (G_OBJECT (dialog_factory->context), "display_changed",
			   G_CALLBACK (gimp_image_dock_factory_display_changed),
			   G_OBJECT (image_dock),
			   0);
287
  g_signal_connect_object (G_OBJECT (dialog_factory->context), "image_changed",
288
			   G_CALLBACK (gimp_image_dock_factory_image_changed),
289
			   G_OBJECT (image_dock),
290
			   0);
Michael Natterer's avatar
Michael Natterer committed
291

292
  g_signal_connect_object (G_OBJECT (context), "image_changed",
293
			   G_CALLBACK (gimp_image_dock_image_changed),
294
			   G_OBJECT (image_dock),
295
			   0);
Michael Natterer's avatar
Michael Natterer committed
296

297
298
  image_dock->menu = gimp_container_menu_new (image_container, context,
                                              DEFAULT_MENU_PREVIEW_HEIGHT);
Michael Natterer's avatar
Michael Natterer committed
299
300
301
302
  gtk_option_menu_set_menu (GTK_OPTION_MENU (image_dock->option_menu),
			    image_dock->menu);
  gtk_widget_show (image_dock->menu);

303
304
  g_object_unref (G_OBJECT (context));

Michael Natterer's avatar
Michael Natterer committed
305
306
  return GTK_WIDGET (image_dock);
}
Michael Natterer's avatar
Michael Natterer committed
307

308
309
310
311
312
313
314
315
316
317
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
318
319
320
321
322
323
324
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)
325
    gtk_widget_show (image_dock->option_menu->parent);
Michael Natterer's avatar
Michael Natterer committed
326
  else
327
    gtk_widget_hide (image_dock->option_menu->parent);
328
329

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

Michael Natterer's avatar
Michael Natterer committed
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
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
347
348
349
350
351
352
353
354
355
356
357
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
358
359
      /*  won't do anything if we already set the display above
       */
Michael Natterer's avatar
Michael Natterer committed
360
361
362
363
364
365
366
367
368
369
370
371
372
      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);

373
  if (! gimage && image_dock->image_container->num_children > 0)
Michael Natterer's avatar
Michael Natterer committed
374
375
376
    {
      gimage = GIMP_IMAGE (gimp_container_get_child_by_index (image_dock->image_container, 0));

377
378
379
380
381
      if (gimage)
	{
	  /*  this invokes this function recursively but we don't enter
	   *  the if() branch the second time
	   */
382
	  gimp_context_set_image (context, gimage);
383
384
385
386

	  /*  stop the emission of the original signal (the emission of
	   *  the recursive signal is finished)
	   */
387
	  g_signal_stop_emission_by_name (G_OBJECT (context), "image_changed");
388
	}
Michael Natterer's avatar
Michael Natterer committed
389
    }
390
391
392
393
394
395
396
397
398
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
  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
438
439
440
441
442
443
444
445
446
447
448
449
450
451
}

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)
    {
452
453
454
      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
455
      else
456
457
        gimp_context_copy_property (dock->dialog_factory->context, dock->context,
                                    GIMP_CONTEXT_PROP_IMAGE);
Michael Natterer's avatar
Michael Natterer committed
458
459
    }
}