diff options
Diffstat (limited to 'app/display/gimpdisplayshell-layer-select.c')
-rw-r--r-- | app/display/gimpdisplayshell-layer-select.c | 305 |
1 files changed, 305 insertions, 0 deletions
diff --git a/app/display/gimpdisplayshell-layer-select.c b/app/display/gimpdisplayshell-layer-select.c new file mode 100644 index 0000000..0618eea --- /dev/null +++ b/app/display/gimpdisplayshell-layer-select.c @@ -0,0 +1,305 @@ +/* GIMP - The GNU 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 3 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, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl.h> +#include <gtk/gtk.h> +#include <gdk/gdkkeysyms.h> + +#include "libgimpwidgets/gimpwidgets.h" + +#include "display-types.h" + +#include "config/gimpcoreconfig.h" + +#include "core/gimp.h" +#include "core/gimpcontainer.h" +#include "core/gimpimage.h" +#include "core/gimplayer.h" + +#include "widgets/gimpview.h" +#include "widgets/gimpviewrenderer.h" + +#include "gimpdisplay.h" +#include "gimpdisplayshell.h" +#include "gimpdisplayshell-layer-select.h" + +#include "gimp-intl.h" + + +typedef struct +{ + GtkWidget *window; + GtkWidget *view; + GtkWidget *label; + + GimpImage *image; + GimpLayer *orig_layer; +} LayerSelect; + + +/* local function prototypes */ + +static LayerSelect * layer_select_new (GimpDisplayShell *shell, + GimpImage *image, + GimpLayer *layer, + gint view_size); +static void layer_select_destroy (LayerSelect *layer_select, + guint32 time); +static void layer_select_advance (LayerSelect *layer_select, + gint move); +static gboolean layer_select_events (GtkWidget *widget, + GdkEvent *event, + LayerSelect *layer_select); + + +/* public functions */ + +void +gimp_display_shell_layer_select_init (GimpDisplayShell *shell, + gint move, + guint32 time) +{ + LayerSelect *layer_select; + GimpImage *image; + GimpLayer *layer; + GdkGrabStatus status; + + g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); + + image = gimp_display_get_image (shell->display); + + layer = gimp_image_get_active_layer (image); + + if (! layer) + return; + + layer_select = layer_select_new (shell, image, layer, + image->gimp->config->layer_preview_size); + layer_select_advance (layer_select, move); + + gtk_window_set_screen (GTK_WINDOW (layer_select->window), + gtk_widget_get_screen (GTK_WIDGET (shell))); + + gtk_widget_show (layer_select->window); + + status = gdk_keyboard_grab (gtk_widget_get_window (layer_select->window), FALSE, time); + if (status != GDK_GRAB_SUCCESS) + g_printerr ("gdk_keyboard_grab failed with status %d\n", status); +} + + +/* private functions */ + +static LayerSelect * +layer_select_new (GimpDisplayShell *shell, + GimpImage *image, + GimpLayer *layer, + gint view_size) +{ + LayerSelect *layer_select; + GtkWidget *frame1; + GtkWidget *frame2; + GtkWidget *hbox; + GtkWidget *alignment; + + layer_select = g_slice_new0 (LayerSelect); + + layer_select->image = image; + layer_select->orig_layer = layer; + + layer_select->window = gtk_window_new (GTK_WINDOW_POPUP); + gtk_window_set_role (GTK_WINDOW (layer_select->window), "gimp-layer-select"); + gtk_window_set_title (GTK_WINDOW (layer_select->window), _("Layer Select")); + gtk_window_set_position (GTK_WINDOW (layer_select->window), GTK_WIN_POS_MOUSE); + gtk_widget_set_events (layer_select->window, + GDK_KEY_PRESS_MASK | + GDK_KEY_RELEASE_MASK | + GDK_BUTTON_PRESS_MASK); + + g_signal_connect (layer_select->window, "event", + G_CALLBACK (layer_select_events), + layer_select); + + frame1 = gtk_frame_new (NULL); + gtk_frame_set_shadow_type (GTK_FRAME (frame1), GTK_SHADOW_OUT); + gtk_container_add (GTK_CONTAINER (layer_select->window), frame1); + gtk_widget_show (frame1); + + frame2 = gtk_frame_new (NULL); + gtk_frame_set_shadow_type (GTK_FRAME (frame2), GTK_SHADOW_IN); + gtk_container_add (GTK_CONTAINER (frame1), frame2); + gtk_widget_show (frame2); + + hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 6); + gtk_container_add (GTK_CONTAINER (frame2), hbox); + gtk_widget_show (hbox); + + /* The view */ + alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0); + gtk_box_pack_start (GTK_BOX (hbox), alignment, FALSE, FALSE, 0); + gtk_widget_show (alignment); + + layer_select->view = + gimp_view_new_by_types (gimp_get_user_context (image->gimp), + GIMP_TYPE_VIEW, + GIMP_TYPE_LAYER, + view_size, 1, FALSE); + gimp_view_renderer_set_color_config (GIMP_VIEW (layer_select->view)->renderer, + gimp_display_shell_get_color_config (shell)); + gimp_view_set_viewable (GIMP_VIEW (layer_select->view), + GIMP_VIEWABLE (layer)); + gtk_container_add (GTK_CONTAINER (alignment), layer_select->view); + gtk_widget_show (layer_select->view); + gtk_widget_show (alignment); + + /* the layer name label */ + layer_select->label = gtk_label_new (gimp_object_get_name (layer)); + gtk_box_pack_start (GTK_BOX (hbox), layer_select->label, FALSE, FALSE, 0); + gtk_widget_show (layer_select->label); + + return layer_select; +} + +static void +layer_select_destroy (LayerSelect *layer_select, + guint32 time) +{ + gdk_display_keyboard_ungrab (gtk_widget_get_display (layer_select->window), + time); + + gtk_widget_destroy (layer_select->window); + + if (layer_select->orig_layer != + gimp_image_get_active_layer (layer_select->image)) + { + gimp_image_flush (layer_select->image); + } + + g_slice_free (LayerSelect, layer_select); +} + +static void +layer_select_advance (LayerSelect *layer_select, + gint move) +{ + GimpLayer *active_layer; + GimpLayer *next_layer; + GList *layers; + gint n_layers; + gint index; + + if (move == 0) + return; + + /* If there is a floating selection, allow no advancement */ + if (gimp_image_get_floating_selection (layer_select->image)) + return; + + active_layer = gimp_image_get_active_layer (layer_select->image); + + layers = gimp_image_get_layer_list (layer_select->image); + n_layers = g_list_length (layers); + + index = g_list_index (layers, active_layer); + index += move; + + if (index < 0) + index = n_layers - 1; + else if (index >= n_layers) + index = 0; + + next_layer = g_list_nth_data (layers, index); + + g_list_free (layers); + + if (next_layer && next_layer != active_layer) + { + active_layer = gimp_image_set_active_layer (layer_select->image, + next_layer); + + if (active_layer) + { + gimp_view_set_viewable (GIMP_VIEW (layer_select->view), + GIMP_VIEWABLE (active_layer)); + gtk_label_set_text (GTK_LABEL (layer_select->label), + gimp_object_get_name (active_layer)); + } + } +} + +static gboolean +layer_select_events (GtkWidget *widget, + GdkEvent *event, + LayerSelect *layer_select) +{ + GdkEventKey *kevent; + GdkEventButton *bevent; + + switch (event->type) + { + case GDK_BUTTON_PRESS: + bevent = (GdkEventButton *) event; + + layer_select_destroy (layer_select, bevent->time); + break; + + case GDK_KEY_PRESS: + kevent = (GdkEventKey *) event; + + switch (kevent->keyval) + { + case GDK_KEY_Tab: + layer_select_advance (layer_select, 1); + break; + case GDK_KEY_ISO_Left_Tab: + layer_select_advance (layer_select, -1); + break; + } + return TRUE; + break; + + case GDK_KEY_RELEASE: + kevent = (GdkEventKey *) event; + + switch (kevent->keyval) + { + case GDK_KEY_Alt_L: case GDK_KEY_Alt_R: + kevent->state &= ~GDK_MOD1_MASK; + break; + case GDK_KEY_Control_L: case GDK_KEY_Control_R: + kevent->state &= ~GDK_CONTROL_MASK; + break; + case GDK_KEY_Shift_L: case GDK_KEY_Shift_R: + kevent->state &= ~GDK_SHIFT_MASK; + break; + } + + if (! (kevent->state & GDK_CONTROL_MASK)) + layer_select_destroy (layer_select, kevent->time); + + return TRUE; + break; + + default: + break; + } + + return FALSE; +} |