diff --git a/app/dialogs/dialogs.c b/app/dialogs/dialogs.c index 6cbabfe6ca..32eaf081fd 100644 --- a/app/dialogs/dialogs.c +++ b/app/dialogs/dialogs.c @@ -242,6 +242,7 @@ static const GimpDialogFactoryEntry entries[] = FOREIGN ("gimp-shear-tool-dialog", TRUE, FALSE), FOREIGN ("gimp-text-tool-dialog", TRUE, TRUE), FOREIGN ("gimp-threshold-tool-dialog", TRUE, FALSE), + FOREIGN ("gimp-transform-3d-tool-dialog", TRUE, FALSE), FOREIGN ("gimp-perspective-tool-dialog", TRUE, FALSE), FOREIGN ("gimp-unified-transform-tool-dialog", TRUE, FALSE), FOREIGN ("gimp-handle-transform-tool-dialog", TRUE, FALSE), diff --git a/app/tools/Makefile.am b/app/tools/Makefile.am index a65543ce89..bbe45841cd 100644 --- a/app/tools/Makefile.am +++ b/app/tools/Makefile.am @@ -214,6 +214,10 @@ libapptools_a_sources = \ gimptooloptions-gui.h \ gimptools-utils.c \ gimptools-utils.h \ + gimptransform3doptions.c \ + gimptransform3doptions.h \ + gimptransform3dtool.c \ + gimptransform3dtool.h \ gimptransformgridoptions.c \ gimptransformgridoptions.h \ gimptransformgridtool.c \ diff --git a/app/tools/gimp-tools.c b/app/tools/gimp-tools.c index 3d8b5ff764..ad1f18c410 100644 --- a/app/tools/gimp-tools.c +++ b/app/tools/gimp-tools.c @@ -84,6 +84,7 @@ #include "gimpsheartool.h" #include "gimpsmudgetool.h" #include "gimptexttool.h" +#include "gimptransform3dtool.h" #include "gimpunifiedtransformtool.h" #include "gimpvectortool.h" #include "gimpwarptool.h" @@ -149,6 +150,7 @@ gimp_tools_init (Gimp *gimp) gimp_shear_tool_register, gimp_handle_transform_tool_register, gimp_perspective_tool_register, + gimp_transform_3d_tool_register, gimp_flip_tool_register, gimp_cage_tool_register, gimp_warp_tool_register, diff --git a/app/tools/gimptransform3doptions.c b/app/tools/gimptransform3doptions.c new file mode 100644 index 0000000000..cec7f1b66a --- /dev/null +++ b/app/tools/gimptransform3doptions.c @@ -0,0 +1,207 @@ +/* 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 . + */ + +#include "config.h" + +#include +#include + +#include "libgimpbase/gimpbase.h" +#include "libgimpconfig/gimpconfig.h" +#include "libgimpwidgets/gimpwidgets.h" + +#include "tools-types.h" + +#include "core/gimp.h" +#include "core/gimptoolinfo.h" + +#include "widgets/gimppropwidgets.h" +#include "widgets/gimpwidgets-utils.h" + +#include "gimptransform3doptions.h" + +#include "gimp-intl.h" + + +enum +{ + PROP_0, + PROP_MODE, + PROP_CONSTRAIN_AXIS, + PROP_Z_AXIS, + PROP_LOCAL_FRAME +}; + + +static void gimp_transform_3d_options_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); +static void gimp_transform_3d_options_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); + + +G_DEFINE_TYPE (GimpTransform3DOptions, gimp_transform_3d_options, + GIMP_TYPE_TRANSFORM_GRID_OPTIONS) + +#define parent_class gimp_transform_3d_options_parent_class + + +static void +gimp_transform_3d_options_class_init (GimpTransform3DOptionsClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->set_property = gimp_transform_3d_options_set_property; + object_class->get_property = gimp_transform_3d_options_get_property; + + GIMP_CONFIG_PROP_ENUM (object_class, PROP_MODE, + "mode", + _("Mode"), + _("Transform mode"), + GIMP_TYPE_TRANSFORM_3D_MODE, + GIMP_TRANSFORM_3D_MODE_CAMERA, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_CONSTRAIN_AXIS, + "constrain-axis", + NULL, + _("Constrain transformation to a single axis"), + FALSE, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_Z_AXIS, + "z-axis", + NULL, + _("Transform along the Z axis"), + FALSE, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_LOCAL_FRAME, + "local-frame", + NULL, + _("Transform in the local frame of reference"), + FALSE, + GIMP_PARAM_STATIC_STRINGS); +} + +static void +gimp_transform_3d_options_init (GimpTransform3DOptions *options) +{ +} + +static void +gimp_transform_3d_options_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpTransform3DOptions *options = GIMP_TRANSFORM_3D_OPTIONS (object); + + switch (property_id) + { + case PROP_MODE: + options->mode = g_value_get_enum (value); + break; + + case PROP_CONSTRAIN_AXIS: + options->constrain_axis = g_value_get_boolean (value); + break; + case PROP_Z_AXIS: + options->z_axis = g_value_get_boolean (value); + break; + case PROP_LOCAL_FRAME: + options->local_frame = g_value_get_boolean (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_transform_3d_options_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpTransform3DOptions *options = GIMP_TRANSFORM_3D_OPTIONS (object); + + switch (property_id) + { + case PROP_MODE: + g_value_set_enum (value, options->mode); + break; + + case PROP_CONSTRAIN_AXIS: + g_value_set_boolean (value, options->constrain_axis); + break; + case PROP_Z_AXIS: + g_value_set_boolean (value, options->z_axis); + break; + case PROP_LOCAL_FRAME: + g_value_set_boolean (value, options->local_frame); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +GtkWidget * +gimp_transform_3d_options_gui (GimpToolOptions *tool_options) +{ + GObject *config = G_OBJECT (tool_options); + GtkWidget *vbox = gimp_transform_grid_options_gui (tool_options); + GtkWidget *button; + gchar *label; + GdkModifierType extend_mask = gimp_get_extend_selection_mask (); + GdkModifierType constrain_mask = gimp_get_constrain_behavior_mask (); + + label = g_strdup_printf (_("Constrain axis (%s)"), + gimp_get_mod_string (extend_mask)); + + button = gimp_prop_check_button_new (config, "constrain-axis", label); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_widget_show (button); + + g_free (label); + + label = g_strdup_printf (_("Z axis (%s)"), + gimp_get_mod_string (constrain_mask)); + + button = gimp_prop_check_button_new (config, "z-axis", label); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_widget_show (button); + + g_free (label); + + label = g_strdup_printf (_("Local frame (%s)"), + gimp_get_mod_string (GDK_MOD1_MASK)); + + button = gimp_prop_check_button_new (config, "local-frame", label); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_widget_show (button); + + g_free (label); + + return vbox; +} diff --git a/app/tools/gimptransform3doptions.h b/app/tools/gimptransform3doptions.h new file mode 100644 index 0000000000..b5aa038490 --- /dev/null +++ b/app/tools/gimptransform3doptions.h @@ -0,0 +1,57 @@ +/* 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 . + */ + +#ifndef __GIMP_TRANSFORM_3D_OPTIONS_H__ +#define __GIMP_TRANSFORM_3D_OPTIONS_H__ + + +#include "gimptransformgridoptions.h" + + +#define GIMP_TYPE_TRANSFORM_3D_OPTIONS (gimp_transform_3d_options_get_type ()) +#define GIMP_TRANSFORM_3D_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_TRANSFORM_3D_OPTIONS, GimpTransform3DOptions)) +#define GIMP_TRANSFORM_3D_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_TRANSFORM_3D_OPTIONS, GimpTransform3DOptionsClass)) +#define GIMP_IS_TRANSFORM_3D_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_TRANSFORM_3D_OPTIONS)) +#define GIMP_IS_TRANSFORM_3D_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_TRANSFORM_3D_OPTIONS)) +#define GIMP_TRANSFORM_3D_OPTIONS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_TRANSFORM_3D_OPTIONS, GimpTransform3DOptionsClass)) + + +typedef struct _GimpTransform3DOptions GimpTransform3DOptions; +typedef struct _GimpTransform3DOptionsClass GimpTransform3DOptionsClass; + +struct _GimpTransform3DOptions +{ + GimpTransformGridOptions parent_instance; + + GimpTransform3DMode mode; + gboolean constrain_axis; + gboolean z_axis; + gboolean local_frame; +}; + +struct _GimpTransform3DOptionsClass +{ + GimpTransformGridOptionsClass parent_class; +}; + + +GType gimp_transform_3d_options_get_type (void) G_GNUC_CONST; + +GtkWidget * gimp_transform_3d_options_gui (GimpToolOptions *tool_options); + + +#endif /* __GIMP_TRANSFORM_3D_OPTIONS_H__ */ diff --git a/app/tools/gimptransform3dtool.c b/app/tools/gimptransform3dtool.c new file mode 100644 index 0000000000..3f3fc83cd8 --- /dev/null +++ b/app/tools/gimptransform3dtool.c @@ -0,0 +1,1030 @@ +/* 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 . + */ + +#include "config.h" + +#include + +#include +#include + +#include "libgimpbase/gimpbase.h" +#include "libgimpmath/gimpmath.h" +#include "libgimpwidgets/gimpwidgets.h" + +#include "tools-types.h" + +#include "core/gimp-transform-3d-utils.h" +#include "core/gimpimage.h" + +#include "widgets/gimphelp-ids.h" +#include "widgets/gimppivotselector.h" +#include "widgets/gimpspinscale.h" +#include "widgets/gimpwidgets-utils.h" + +#include "display/gimpdisplay.h" +#include "display/gimpdisplayshell.h" +#include "display/gimpdisplayshell-transform.h" +#include "display/gimptoolgui.h" +#include "display/gimptooltransform3dgrid.h" + +#include "gimptoolcontrol.h" +#include "gimptransform3doptions.h" +#include "gimptransform3dtool.h" + +#include "gimp-intl.h" + + +/* index into trans_info array */ +enum +{ + VANISHING_POINT_X, + VANISHING_POINT_Y, + LENS_MODE, + LENS_VALUE, + OFFSET_X, + OFFSET_Y, + OFFSET_Z, + ROTATION_ORDER, + ANGLE_X, + ANGLE_Y, + ANGLE_Z, + PIVOT_X, + PIVOT_Y, + PIVOT_Z +}; + + +/* local function prototypes */ + +static void gimp_transform_3d_tool_modifier_key (GimpTool *tool, + GdkModifierType key, + gboolean press, + GdkModifierType state, + GimpDisplay *display); + +static gboolean gimp_transform_3d_tool_info_to_matrix (GimpTransformGridTool *tg_tool, + GimpMatrix3 *transform); +static void gimp_transform_3d_tool_dialog (GimpTransformGridTool *tg_tool); +static void gimp_transform_3d_tool_dialog_update (GimpTransformGridTool *tg_tool); +static void gimp_transform_3d_tool_prepare (GimpTransformGridTool *tg_tool); +static GimpToolWidget * gimp_transform_3d_tool_get_widget (GimpTransformGridTool *tg_tool); +static void gimp_transform_3d_tool_update_widget (GimpTransformGridTool *tg_tool); +static void gimp_transform_3d_tool_widget_changed (GimpTransformGridTool *tg_tool); + +static void gimp_transform_3d_tool_dialog_changed (GObject *object, + GimpTransform3DTool *t3d); +static void gimp_transform_3d_tool_lens_mode_changed (GtkComboBox *combo, + GimpTransform3DTool *t3d); +static void gimp_transform_3d_tool_rotation_order_clicked (GtkButton *button, + GimpTransform3DTool *t3d); +static void gimp_transform_3d_tool_pivot_changed (GimpPivotSelector *selector, + GimpTransform3DTool *t3d); + +static gdouble gimp_transform_3d_tool_get_focal_length (GimpTransform3DTool *t3d); + + +G_DEFINE_TYPE (GimpTransform3DTool, gimp_transform_3d_tool, GIMP_TYPE_TRANSFORM_GRID_TOOL) + +#define parent_class gimp_transform_3d_tool_parent_class + + +void +gimp_transform_3d_tool_register (GimpToolRegisterCallback callback, + gpointer data) +{ + (* callback) (GIMP_TYPE_TRANSFORM_3D_TOOL, + GIMP_TYPE_TRANSFORM_3D_OPTIONS, + gimp_transform_3d_options_gui, + GIMP_CONTEXT_PROP_MASK_BACKGROUND, + "gimp-transform-3d-tool", + _("3D Transform"), + _("3D Transform Tool: Apply a 3D transformation to the layer, selection or path"), + N_("_3D Transform"), "W", + NULL, GIMP_ICON_TOOL_TRANSFORM_3D, + GIMP_ICON_TOOL_TRANSFORM_3D, + data); +} + +static void +gimp_transform_3d_tool_class_init (GimpTransform3DToolClass *klass) +{ + GimpToolClass *tool_class = GIMP_TOOL_CLASS (klass); + GimpTransformToolClass *tr_class = GIMP_TRANSFORM_TOOL_CLASS (klass); + GimpTransformGridToolClass *tg_class = GIMP_TRANSFORM_GRID_TOOL_CLASS (klass); + + tool_class->modifier_key = gimp_transform_3d_tool_modifier_key; + + tg_class->info_to_matrix = gimp_transform_3d_tool_info_to_matrix; + tg_class->dialog = gimp_transform_3d_tool_dialog; + tg_class->dialog_update = gimp_transform_3d_tool_dialog_update; + tg_class->prepare = gimp_transform_3d_tool_prepare; + tg_class->get_widget = gimp_transform_3d_tool_get_widget; + tg_class->update_widget = gimp_transform_3d_tool_update_widget; + tg_class->widget_changed = gimp_transform_3d_tool_widget_changed; + + tr_class->undo_desc = C_("undo-type", "3D Transform"); + tr_class->progress_text = _("3D transformation"); +} + +static void +gimp_transform_3d_tool_init (GimpTransform3DTool *t3d) +{ +} + +static void +gimp_transform_3d_tool_modifier_key (GimpTool *tool, + GdkModifierType key, + gboolean press, + GdkModifierType state, + GimpDisplay *display) +{ + GimpTransform3DOptions *options = GIMP_TRANSFORM_3D_TOOL_GET_OPTIONS (tool); + + if (key == gimp_get_extend_selection_mask ()) + { + g_object_set (options, + "constrain-axis", ! options->constrain_axis, + NULL); + } + else if (key == gimp_get_constrain_behavior_mask ()) + { + g_object_set (options, + "z-axis", ! options->z_axis, + NULL); + } + else if (key == GDK_MOD1_MASK) + { + g_object_set (options, + "local-frame", ! options->local_frame, + NULL); + } +} + +static gboolean +gimp_transform_3d_tool_info_to_matrix (GimpTransformGridTool *tg_tool, + GimpMatrix3 *transform) +{ + GimpTransform3DTool *t3d = GIMP_TRANSFORM_3D_TOOL (tg_tool); + + gimp_transform_3d_matrix (transform, + + tg_tool->trans_info[VANISHING_POINT_X], + tg_tool->trans_info[VANISHING_POINT_Y], + -gimp_transform_3d_tool_get_focal_length (t3d), + + tg_tool->trans_info[OFFSET_X], + tg_tool->trans_info[OFFSET_Y], + tg_tool->trans_info[OFFSET_Z], + + tg_tool->trans_info[ROTATION_ORDER], + tg_tool->trans_info[ANGLE_X], + tg_tool->trans_info[ANGLE_Y], + tg_tool->trans_info[ANGLE_Z], + + tg_tool->trans_info[PIVOT_X], + tg_tool->trans_info[PIVOT_Y], + tg_tool->trans_info[PIVOT_Z]); + + return TRUE; +} + +static void +gimp_transform_3d_tool_dialog (GimpTransformGridTool *tg_tool) +{ + GimpTransform3DTool *t3d = GIMP_TRANSFORM_3D_TOOL (tg_tool); + GimpTransform3DOptions *options = GIMP_TRANSFORM_3D_TOOL_GET_OPTIONS (tg_tool); + GtkWidget *notebook; + GtkWidget *label; + GtkWidget *vbox; + GtkWidget *frame; + GtkWidget *vbox2; + GtkWidget *se; + GtkWidget *spinbutton; + GtkWidget *combo; + GtkWidget *scale; + GtkWidget *grid; + GtkWidget *button; + GtkWidget *selector; + gint i; + + /* main notebook */ + notebook = gtk_notebook_new (); + gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_LEFT); + gtk_box_pack_start (GTK_BOX (gimp_tool_gui_get_vbox (tg_tool->gui)), + notebook, FALSE, FALSE, 0); + gtk_widget_show (notebook); + + t3d->notebook = notebook; + + /* camera page */ + label = gtk_image_new_from_icon_name (GIMP_ICON_TRANSFORM_3D_CAMERA, + GTK_ICON_SIZE_MENU); + gimp_help_set_help_data (label, _("Camera"), NULL); + gtk_widget_show (label); + + vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2); + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox, label); + gtk_widget_show (vbox); + + /* vanishing-point frame */ + frame = gimp_frame_new (_("Vanishing Point")); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0); + gtk_widget_show (frame); + + vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2); + gtk_container_add (GTK_CONTAINER (frame), vbox2); + gtk_widget_show (vbox2); + + /* vanishing-point size entry */ + se = gimp_size_entry_new (1, GIMP_UNIT_PIXEL, "%a", TRUE, TRUE, FALSE, 6, + GIMP_SIZE_ENTRY_UPDATE_SIZE); + gtk_grid_set_row_spacing (GTK_GRID (se), 2); + gtk_grid_set_column_spacing (GTK_GRID (se), 2); + gtk_box_pack_start (GTK_BOX (vbox2), se, FALSE, FALSE, 0); + gtk_widget_show (se); + + t3d->vanishing_point_se = se; + + spinbutton = gimp_spin_button_new_with_range (0.0, 0.0, 1.0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE); + gtk_entry_set_width_chars (GTK_ENTRY (spinbutton), 6); + gimp_size_entry_add_field (GIMP_SIZE_ENTRY (se), + GTK_SPIN_BUTTON (spinbutton), NULL); + gtk_grid_attach (GTK_GRID (se), spinbutton, 1, 0, 1, 1); + gtk_widget_show (spinbutton); + + gimp_size_entry_attach_label (GIMP_SIZE_ENTRY (se), _("_X:"), 0, 0, 0.0); + gimp_size_entry_attach_label (GIMP_SIZE_ENTRY (se), _("_Y:"), 1, 0, 0.0); + + gimp_size_entry_set_refval_digits (GIMP_SIZE_ENTRY (se), 0, 2); + gimp_size_entry_set_refval_digits (GIMP_SIZE_ENTRY (se), 1, 2); + + g_signal_connect (se, "value-changed", + G_CALLBACK (gimp_transform_3d_tool_dialog_changed), + t3d); + + /* lens frame */ + frame = gimp_frame_new (NULL); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0); + gtk_widget_show (frame); + + /* lens-mode combo */ + combo = gimp_enum_combo_box_new (GIMP_TYPE_TRANSFORM_3D_LENS_MODE); + gtk_frame_set_label_widget (GTK_FRAME (frame), combo); + gtk_widget_show (combo); + + t3d->lens_mode_combo = combo; + + g_signal_connect (combo, "changed", + G_CALLBACK (gimp_transform_3d_tool_lens_mode_changed), + t3d); + + vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2); + gtk_container_add (GTK_CONTAINER (frame), vbox2); + gtk_widget_show (vbox2); + + /* focal-length size entry */ + se = gimp_size_entry_new (1, GIMP_UNIT_PIXEL, "%a", TRUE, FALSE, FALSE, 6, + GIMP_SIZE_ENTRY_UPDATE_SIZE); + gtk_grid_set_row_spacing (GTK_GRID (se), 2); + gtk_box_pack_start (GTK_BOX (vbox2), se, FALSE, FALSE, 0); + + t3d->focal_length_se = se; + + gimp_size_entry_set_refval_digits (GIMP_SIZE_ENTRY (se), 0, 2); + + gimp_size_entry_set_value_boundaries (GIMP_SIZE_ENTRY (se), 0, + 0.0, G_MAXDOUBLE); + + g_signal_connect (se, "value-changed", + G_CALLBACK (gimp_transform_3d_tool_dialog_changed), + t3d); + + /* angle-of-view spin scale */ + t3d->angle_of_view_adj = (GtkAdjustment *) + gtk_adjustment_new (0, 0, 180, 1, 10, 0); + scale = gimp_spin_scale_new (t3d->angle_of_view_adj, + _("Angle"), 2); + gtk_box_pack_start (GTK_BOX (vbox2), scale, FALSE, FALSE, 0); + gtk_widget_show (scale); + + t3d->angle_of_view_scale = scale; + + g_signal_connect (t3d->angle_of_view_adj, "value-changed", + G_CALLBACK (gimp_transform_3d_tool_dialog_changed), + t3d); + + /* move page */ + label = gtk_image_new_from_icon_name (GIMP_ICON_TRANSFORM_3D_MOVE, + GTK_ICON_SIZE_MENU); + gimp_help_set_help_data (label, _("Move"), NULL); + gtk_widget_show (label); + + vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2); + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox, label); + gtk_widget_show (vbox); + + /* offset frame */ + frame = gimp_frame_new (_("Offset")); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0); + gtk_widget_show (frame); + + vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2); + gtk_container_add (GTK_CONTAINER (frame), vbox2); + gtk_widget_show (vbox2); + + /* offset size entry */ + se = gimp_size_entry_new (1, GIMP_UNIT_PIXEL, "%a", TRUE, TRUE, FALSE, 6, + GIMP_SIZE_ENTRY_UPDATE_SIZE); + gtk_grid_set_row_spacing (GTK_GRID (se), 2); + gtk_grid_set_column_spacing (GTK_GRID (se), 2); + gtk_box_pack_start (GTK_BOX (vbox2), se, FALSE, FALSE, 0); + gtk_widget_show (se); + + t3d->offset_se = se; + + grid = gtk_grid_new (); + gtk_grid_set_row_spacing (GTK_GRID (grid), 2); + gtk_grid_set_column_spacing (GTK_GRID (grid), 2); + gtk_grid_attach (GTK_GRID (se), grid, 0, 0, 2, 1); + gtk_widget_show (grid); + + spinbutton = gimp_spin_button_new_with_range (0.0, 0.0, 1.0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE); + gtk_entry_set_width_chars (GTK_ENTRY (spinbutton), 6); + gimp_size_entry_add_field (GIMP_SIZE_ENTRY (se), + GTK_SPIN_BUTTON (spinbutton), NULL); + gtk_grid_attach (GTK_GRID (grid), spinbutton, 1, 1, 1, 1); + gtk_widget_show (spinbutton); + + spinbutton = gimp_spin_button_new_with_range (0.0, 0.0, 1.0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE); + gtk_entry_set_width_chars (GTK_ENTRY (spinbutton), 6); + gimp_size_entry_add_field (GIMP_SIZE_ENTRY (se), + GTK_SPIN_BUTTON (spinbutton), NULL); + gtk_grid_attach (GTK_GRID (grid), spinbutton, 1, 0, 1, 1); + gtk_widget_show (spinbutton); + + label = gtk_label_new_with_mnemonic (_("_X:")); + gtk_label_set_xalign (GTK_LABEL (label), 0.0); + gtk_grid_attach (GTK_GRID (grid), label, 0, 0, 1, 1); + gtk_widget_show (label); + + label = gtk_label_new_with_mnemonic (_("_Y:")); + gtk_label_set_xalign (GTK_LABEL (label), 0.0); + gtk_grid_attach (GTK_GRID (grid), label, 0, 1, 1, 1); + gtk_widget_show (label); + + label = gtk_label_new_with_mnemonic (_("_Z:")); + gtk_label_set_xalign (GTK_LABEL (label), 0.0); + gtk_grid_attach (GTK_GRID (se), label, 0, 1, 1, 1); + gtk_widget_show (label); + + gimp_size_entry_set_refval_boundaries (GIMP_SIZE_ENTRY (se), 0, + -GIMP_MAX_IMAGE_SIZE, + GIMP_MAX_IMAGE_SIZE); + gimp_size_entry_set_refval_boundaries (GIMP_SIZE_ENTRY (se), 1, + -GIMP_MAX_IMAGE_SIZE, + GIMP_MAX_IMAGE_SIZE); + gimp_size_entry_set_refval_boundaries (GIMP_SIZE_ENTRY (se), 2, + -GIMP_MAX_IMAGE_SIZE, + GIMP_MAX_IMAGE_SIZE); + + gimp_size_entry_set_refval_digits (GIMP_SIZE_ENTRY (se), 0, 2); + gimp_size_entry_set_refval_digits (GIMP_SIZE_ENTRY (se), 1, 2); + gimp_size_entry_set_refval_digits (GIMP_SIZE_ENTRY (se), 2, 2); + + g_signal_connect (se, "value-changed", + G_CALLBACK (gimp_transform_3d_tool_dialog_changed), + t3d); + + /* rotate page */ + label = gtk_image_new_from_icon_name (GIMP_ICON_TRANSFORM_3D_ROTATE, + GTK_ICON_SIZE_MENU); + gimp_help_set_help_data (label, _("Rotate"), NULL); + gtk_widget_show (label); + + /* angle frame */ + frame = gimp_frame_new (_("Angle")); + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), frame, label); + gtk_widget_show (frame); + + grid = gtk_grid_new (); + gtk_grid_set_row_spacing (GTK_GRID (grid), 2); + gtk_grid_set_column_spacing (GTK_GRID (grid), 2); + gtk_container_add (GTK_CONTAINER (frame), grid); + gtk_widget_show (grid); + + for (i = 0; i < 3; i++) + { + const gchar *labels[3] = {_("X"), _("Y"), _("Z")}; + + /* rotation-order button */ + button = gtk_button_new (); + gimp_help_set_help_data (button, _("Rotation axis order"), NULL); + gtk_grid_attach (GTK_GRID (grid), button, 0, i, 1, 1); + gtk_widget_show (button); + + t3d->rotation_order_buttons[i] = button; + + g_signal_connect (button, "clicked", + G_CALLBACK (gimp_transform_3d_tool_rotation_order_clicked), + t3d); + + /* angle spin scale */ + t3d->angle_adj[i] = (GtkAdjustment *) + gtk_adjustment_new (0, -180, 180, 1, 10, 0); + scale = gimp_spin_scale_new (t3d->angle_adj[i], + labels[i], 2); + gtk_widget_set_hexpand (GTK_WIDGET (scale), TRUE); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (scale), TRUE); + gtk_grid_attach (GTK_GRID (grid), scale, 1, i, 1, 1); + gtk_widget_show (scale); + + g_signal_connect (t3d->angle_adj[i], "value-changed", + G_CALLBACK (gimp_transform_3d_tool_dialog_changed), + t3d); + } + + /* pivot selector */ + selector = gimp_pivot_selector_new (0.0, 0.0, 0.0, 0.0); + gtk_grid_attach (GTK_GRID (grid), selector, 2, 0, 1, 3); + gtk_widget_show (selector); + + t3d->pivot_selector = selector; + + g_signal_connect (selector, "changed", + G_CALLBACK (gimp_transform_3d_tool_pivot_changed), + t3d); + + g_object_bind_property (options, "mode", + t3d->notebook, "page", + G_BINDING_SYNC_CREATE | + G_BINDING_BIDIRECTIONAL); +} + +static void +gimp_transform_3d_tool_dialog_update (GimpTransformGridTool *tg_tool) +{ + GimpTransform3DTool *t3d = GIMP_TRANSFORM_3D_TOOL (tg_tool); + Gimp3DTrasnformLensMode lens_mode; + gint permutation[3]; + gint i; + + t3d->updating = TRUE; + + /* vanishing-point size entry */ + gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (t3d->vanishing_point_se), + 0, tg_tool->trans_info[VANISHING_POINT_X]); + gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (t3d->vanishing_point_se), + 1, tg_tool->trans_info[VANISHING_POINT_Y]); + + lens_mode = tg_tool->trans_info[LENS_MODE]; + + /* lens-mode combo */ + gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (t3d->lens_mode_combo), + lens_mode); + + /* focal-length size entry / angle-of-view spin scale */ + gtk_widget_set_visible (t3d->focal_length_se, + lens_mode == + GIMP_TRANSFORM_3D_LENS_MODE_FOCAL_LENGTH); + gtk_widget_set_visible (t3d->angle_of_view_scale, + lens_mode != + GIMP_TRANSFORM_3D_LENS_MODE_FOCAL_LENGTH); + + switch (lens_mode) + { + case GIMP_TRANSFORM_3D_LENS_MODE_FOCAL_LENGTH: + gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (t3d->focal_length_se), + 0, tg_tool->trans_info[LENS_VALUE]); + break; + + case GIMP_TRANSFORM_3D_LENS_MODE_FOV_IMAGE: + case GIMP_TRANSFORM_3D_LENS_MODE_FOV_ITEM: + gtk_adjustment_set_value ( + t3d->angle_of_view_adj, + gimp_rad_to_deg (tg_tool->trans_info[LENS_VALUE])); + break; + } + + /* offset size entry */ + gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (t3d->offset_se), + 0, tg_tool->trans_info[OFFSET_X]); + gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (t3d->offset_se), + 1, tg_tool->trans_info[OFFSET_Y]); + gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (t3d->offset_se), + 2, tg_tool->trans_info[OFFSET_Z]); + + /* rotation-order buttons */ + gimp_transform_3d_rotation_order_to_permutation ( + tg_tool->trans_info[ROTATION_ORDER], permutation); + + for (i = 0; i < 3; i++) + { + gchar *label; + + label = g_strdup_printf ("%d", i + 1); + + gtk_button_set_label ( + GTK_BUTTON (t3d->rotation_order_buttons[permutation[i]]), label); + + g_free (label); + } + + /* angle spin scales */ + gtk_adjustment_set_value (t3d->angle_adj[0], + gimp_rad_to_deg (tg_tool->trans_info[ANGLE_X])); + gtk_adjustment_set_value (t3d->angle_adj[1], + gimp_rad_to_deg (tg_tool->trans_info[ANGLE_Y])); + gtk_adjustment_set_value (t3d->angle_adj[2], + gimp_rad_to_deg (tg_tool->trans_info[ANGLE_Z])); + + /* pivot selector */ + gimp_pivot_selector_set_position (GIMP_PIVOT_SELECTOR (t3d->pivot_selector), + tg_tool->trans_info[PIVOT_X], + tg_tool->trans_info[PIVOT_Y]); + + t3d->updating = FALSE; +} + +static void +gimp_transform_3d_tool_prepare (GimpTransformGridTool *tg_tool) +{ + GimpTool *tool = GIMP_TOOL (tg_tool); + GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (tg_tool); + GimpTransform3DTool *t3d = GIMP_TRANSFORM_3D_TOOL (tg_tool); + GimpDisplay *display = tool->display; + GimpDisplayShell *shell = gimp_display_get_shell (display); + GimpImage *image = gimp_display_get_image (display); + GimpSizeEntry *se; + gdouble xres; + gdouble yres; + gint width; + gint height; + + gimp_image_get_resolution (image, &xres, &yres); + + width = gimp_image_get_width (image); + height = gimp_image_get_height (image); + + tg_tool->trans_info[VANISHING_POINT_X] = (tr_tool->x1 + tr_tool->x2) / 2.0; + tg_tool->trans_info[VANISHING_POINT_Y] = (tr_tool->y1 + tr_tool->y2) / 2.0; + + tg_tool->trans_info[LENS_MODE] = GIMP_TRANSFORM_3D_LENS_MODE_FOV_ITEM; + tg_tool->trans_info[LENS_VALUE] = gimp_deg_to_rad (45.0); + + tg_tool->trans_info[OFFSET_X] = 0.0; + tg_tool->trans_info[OFFSET_Y] = 0.0; + tg_tool->trans_info[OFFSET_Z] = 0.0; + + tg_tool->trans_info[ROTATION_ORDER] = + gimp_transform_3d_permutation_to_rotation_order ((const gint[]) {0, 1, 2}); + tg_tool->trans_info[ANGLE_X] = 0.0; + tg_tool->trans_info[ANGLE_Y] = 0.0; + tg_tool->trans_info[ANGLE_Z] = 0.0; + + tg_tool->trans_info[PIVOT_X] = (tr_tool->x1 + tr_tool->x2) / 2.0; + tg_tool->trans_info[PIVOT_Y] = (tr_tool->y1 + tr_tool->y2) / 2.0; + tg_tool->trans_info[PIVOT_Z] = 0.0; + + t3d->updating = TRUE; + + /* vanishing-point size entry */ + se = GIMP_SIZE_ENTRY (t3d->vanishing_point_se); + + gimp_size_entry_set_unit (se, shell->unit); + + gimp_size_entry_set_resolution (se, 0, xres, FALSE); + gimp_size_entry_set_resolution (se, 1, yres, FALSE); + + gimp_size_entry_set_refval_boundaries (se, 0, + -GIMP_MAX_IMAGE_SIZE, + GIMP_MAX_IMAGE_SIZE); + gimp_size_entry_set_refval_boundaries (se, 1, + -GIMP_MAX_IMAGE_SIZE, + GIMP_MAX_IMAGE_SIZE); + + gimp_size_entry_set_size (se, 0, tr_tool->x1, tr_tool->x2); + gimp_size_entry_set_size (se, 1, tr_tool->y1, tr_tool->y2); + + /* focal-length size entry */ + se = GIMP_SIZE_ENTRY (t3d->focal_length_se); + + gimp_size_entry_set_unit (se, shell->unit); + + gimp_size_entry_set_resolution (se, 0, width >= height ? xres : yres, FALSE); + + /* offset size entry */ + se = GIMP_SIZE_ENTRY (t3d->offset_se); + + gimp_size_entry_set_unit (se, shell->unit); + + gimp_size_entry_set_resolution (se, 0, xres, FALSE); + gimp_size_entry_set_resolution (se, 1, yres, FALSE); + gimp_size_entry_set_resolution (se, 2, width >= height ? xres : yres, FALSE); + + gimp_size_entry_set_size (se, 0, 0, width); + gimp_size_entry_set_size (se, 1, 0, height); + gimp_size_entry_set_size (se, 2, 0, MAX (width, height)); + + /* pivot selector */ + gimp_pivot_selector_set_bounds (GIMP_PIVOT_SELECTOR (t3d->pivot_selector), + tr_tool->x1, tr_tool->y1, + tr_tool->x2, tr_tool->y2); + + t3d->updating = FALSE; +} + +static GimpToolWidget * +gimp_transform_3d_tool_get_widget (GimpTransformGridTool *tg_tool) +{ + GimpTool *tool = GIMP_TOOL (tg_tool); + GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (tg_tool); + GimpTransform3DTool *t3d = GIMP_TRANSFORM_3D_TOOL (tg_tool); + GimpTransform3DOptions *options = GIMP_TRANSFORM_3D_TOOL_GET_OPTIONS (tg_tool); + GimpDisplayShell *shell = gimp_display_get_shell (tool->display); + GimpToolWidget *widget; + gint i; + + static const gchar *bound_properties[] = + { + "mode", + "constrain-axis", + "z-axis", + "local-frame", + }; + + widget = gimp_tool_transform_3d_grid_new ( + shell, + tr_tool->x1, + tr_tool->y1, + tr_tool->x2, + tr_tool->y2, + tg_tool->trans_info[VANISHING_POINT_X], + tg_tool->trans_info[VANISHING_POINT_Y], + -gimp_transform_3d_tool_get_focal_length (t3d)); + + for (i = 0; i < G_N_ELEMENTS (bound_properties); i++) + { + g_object_bind_property (options, bound_properties[i], + widget, bound_properties[i], + G_BINDING_SYNC_CREATE | + G_BINDING_BIDIRECTIONAL); + } + + return widget; +} + +static void +gimp_transform_3d_tool_update_widget (GimpTransformGridTool *tg_tool) +{ + GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (tg_tool); + GimpTransform3DTool *t3d = GIMP_TRANSFORM_3D_TOOL (tg_tool); + GimpMatrix3 transform; + + GIMP_TRANSFORM_GRID_TOOL_CLASS (parent_class)->update_widget (tg_tool); + + gimp_transform_grid_tool_info_to_matrix (tg_tool, &transform); + + g_object_set ( + tg_tool->widget, + + "x1", (gdouble) tr_tool->x1, + "y1", (gdouble) tr_tool->y1, + "x2", (gdouble) tr_tool->x2, + "y2", (gdouble) tr_tool->y2, + + "camera-x", tg_tool->trans_info[VANISHING_POINT_X], + "camera-y", tg_tool->trans_info[VANISHING_POINT_Y], + "camera-z", -gimp_transform_3d_tool_get_focal_length (t3d), + + "offset-x", tg_tool->trans_info[OFFSET_X], + "offset-y", tg_tool->trans_info[OFFSET_Y], + "offset-z", tg_tool->trans_info[OFFSET_Z], + + "rotation-order", (gint) tg_tool->trans_info[ROTATION_ORDER], + "angle-x", tg_tool->trans_info[ANGLE_X], + "angle-y", tg_tool->trans_info[ANGLE_Y], + "angle-z", tg_tool->trans_info[ANGLE_Z], + + "pivot-3d-x", tg_tool->trans_info[PIVOT_X], + "pivot-3d-y", tg_tool->trans_info[PIVOT_Y], + "pivot-3d-z", tg_tool->trans_info[PIVOT_Z], + + "transform", &transform, + + NULL); +} + +static void +gimp_transform_3d_tool_widget_changed (GimpTransformGridTool *tg_tool) +{ + g_object_get ( + tg_tool->widget, + + "camera-x", &tg_tool->trans_info[VANISHING_POINT_X], + "camera-y", &tg_tool->trans_info[VANISHING_POINT_Y], + + "offset-x", &tg_tool->trans_info[OFFSET_X], + "offset-y", &tg_tool->trans_info[OFFSET_Y], + "offset-z", &tg_tool->trans_info[OFFSET_Z], + + "angle-x", &tg_tool->trans_info[ANGLE_X], + "angle-y", &tg_tool->trans_info[ANGLE_Y], + "angle-z", &tg_tool->trans_info[ANGLE_Z], + + NULL); + + GIMP_TRANSFORM_GRID_TOOL_CLASS (parent_class)->widget_changed (tg_tool); +} + +static void +gimp_transform_3d_tool_dialog_changed (GObject *object, + GimpTransform3DTool *t3d) +{ + GimpTool *tool = GIMP_TOOL (t3d); + GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (t3d); + GimpTransformGridTool *tg_tool = GIMP_TRANSFORM_GRID_TOOL (t3d); + + if (t3d->updating) + return; + + /* vanishing-point size entry */ + tg_tool->trans_info[VANISHING_POINT_X] = gimp_size_entry_get_refval ( + GIMP_SIZE_ENTRY (t3d->vanishing_point_se), 0); + tg_tool->trans_info[VANISHING_POINT_Y] = gimp_size_entry_get_refval ( + GIMP_SIZE_ENTRY (t3d->vanishing_point_se), 1); + + /* focal-length size entry / angle-of-view spin scale */ + switch ((gint) tg_tool->trans_info[LENS_MODE]) + { + case GIMP_TRANSFORM_3D_LENS_MODE_FOCAL_LENGTH: + tg_tool->trans_info[LENS_VALUE] = gimp_size_entry_get_refval ( + GIMP_SIZE_ENTRY (t3d->focal_length_se), 0); + break; + + case GIMP_TRANSFORM_3D_LENS_MODE_FOV_IMAGE: + case GIMP_TRANSFORM_3D_LENS_MODE_FOV_ITEM: + tg_tool->trans_info[LENS_VALUE] = gimp_deg_to_rad ( + gtk_adjustment_get_value (t3d->angle_of_view_adj)); + break; + } + + /* offset size entry */ + tg_tool->trans_info[OFFSET_X] = gimp_size_entry_get_refval ( + GIMP_SIZE_ENTRY (t3d->offset_se), 0); + tg_tool->trans_info[OFFSET_Y] = gimp_size_entry_get_refval ( + GIMP_SIZE_ENTRY (t3d->offset_se), 1); + tg_tool->trans_info[OFFSET_Z] = gimp_size_entry_get_refval ( + GIMP_SIZE_ENTRY (t3d->offset_se), 2); + + /* angle spin scales */ + tg_tool->trans_info[ANGLE_X] = gimp_deg_to_rad (gtk_adjustment_get_value ( + t3d->angle_adj[0])); + tg_tool->trans_info[ANGLE_Y] = gimp_deg_to_rad (gtk_adjustment_get_value ( + t3d->angle_adj[1])); + tg_tool->trans_info[ANGLE_Z] = gimp_deg_to_rad (gtk_adjustment_get_value ( + t3d->angle_adj[2])); + + gimp_transform_grid_tool_push_internal_undo (tg_tool, TRUE); + + gimp_transform_tool_recalc_matrix (tr_tool, tool->display); +} + +static void +gimp_transform_3d_tool_lens_mode_changed (GtkComboBox *combo, + GimpTransform3DTool *t3d) +{ + GimpTool *tool = GIMP_TOOL (t3d); + GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (t3d); + GimpTransformGridTool *tg_tool = GIMP_TRANSFORM_GRID_TOOL (t3d); + GimpDisplay *display = tool->display; + GimpImage *image = gimp_display_get_image (display); + gdouble x1 = 0.0; + gdouble y1 = 0.0; + gdouble x2 = 0.0; + gdouble y2 = 0.0; + gint width; + gint height; + gint lens_mode; + gdouble focal_length; + + if (t3d->updating) + return; + + if (! gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (combo), &lens_mode)) + return; + + width = gimp_image_get_width (image); + height = gimp_image_get_height (image); + + focal_length = gimp_transform_3d_tool_get_focal_length (t3d); + + tg_tool->trans_info[LENS_MODE] = lens_mode; + + switch (lens_mode) + { + case GIMP_TRANSFORM_3D_LENS_MODE_FOCAL_LENGTH: + case GIMP_TRANSFORM_3D_LENS_MODE_FOV_IMAGE: + x1 = 0.0; + y1 = 0.0; + + x2 = width; + y2 = height; + break; + + case GIMP_TRANSFORM_3D_LENS_MODE_FOV_ITEM: + x1 = tr_tool->x1; + y1 = tr_tool->y1; + + x2 = tr_tool->x2; + y2 = tr_tool->y2; + break; + } + + switch (lens_mode) + { + case GIMP_TRANSFORM_3D_LENS_MODE_FOCAL_LENGTH: + tg_tool->trans_info[LENS_VALUE] = focal_length; + break; + + case GIMP_TRANSFORM_3D_LENS_MODE_FOV_IMAGE: + case GIMP_TRANSFORM_3D_LENS_MODE_FOV_ITEM: + tg_tool->trans_info[LENS_VALUE] = + gimp_transform_3d_focal_length_to_angle_of_view ( + focal_length, x2 - x1, y2 - y1); + break; + } + + /* vanishing-point size entry */ + gimp_size_entry_set_size (GIMP_SIZE_ENTRY (t3d->vanishing_point_se), 0, + x1, x2); + gimp_size_entry_set_size (GIMP_SIZE_ENTRY (t3d->vanishing_point_se), 1, + y1, y2); + + gimp_transform_grid_tool_push_internal_undo (tg_tool, TRUE); + + gimp_transform_tool_recalc_matrix (tr_tool, tool->display); +} + +static void +gimp_transform_3d_tool_rotation_order_clicked (GtkButton *button, + GimpTransform3DTool *t3d) +{ + GimpTool *tool = GIMP_TOOL (t3d); + GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (t3d); + GimpTransformGridTool *tg_tool = GIMP_TRANSFORM_GRID_TOOL (t3d); + GimpMatrix4 matrix; + gint permutation[3]; + gint b; + gint i; + + for (b = 0; b < 3; b++) + { + if (GTK_BUTTON (t3d->rotation_order_buttons[b]) == button) + break; + } + + gimp_transform_3d_rotation_order_to_permutation ( + tg_tool->trans_info[ROTATION_ORDER], permutation); + + if (permutation[0] == b) + { + gint temp; + + temp = permutation[1]; + permutation[1] = permutation[2]; + permutation[2] = temp; + } + else + { + gint temp; + + temp = permutation[0]; + permutation[0] = b; + + for (i = 1; i < 3; i++) + { + if (permutation[i] == b) + { + permutation[i] = temp; + + break; + } + } + } + + gimp_matrix4_identity (&matrix); + + gimp_transform_3d_matrix4_rotate_euler (&matrix, + tg_tool->trans_info[ROTATION_ORDER], + tg_tool->trans_info[ANGLE_X], + tg_tool->trans_info[ANGLE_Y], + tg_tool->trans_info[ANGLE_Z], + 0.0, 0.0, 0.0); + + tg_tool->trans_info[ROTATION_ORDER] = + gimp_transform_3d_permutation_to_rotation_order (permutation); + + gimp_transform_3d_matrix4_rotate_euler_decompose ( + &matrix, + tg_tool->trans_info[ROTATION_ORDER], + &tg_tool->trans_info[ANGLE_X], + &tg_tool->trans_info[ANGLE_Y], + &tg_tool->trans_info[ANGLE_Z]); + + gimp_transform_grid_tool_push_internal_undo (tg_tool, TRUE); + + gimp_transform_tool_recalc_matrix (tr_tool, tool->display); +} + +static void +gimp_transform_3d_tool_pivot_changed (GimpPivotSelector *selector, + GimpTransform3DTool *t3d) +{ + GimpTool *tool = GIMP_TOOL (t3d); + GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (t3d); + GimpTransformGridTool *tg_tool = GIMP_TRANSFORM_GRID_TOOL (t3d); + GimpMatrix4 matrix; + gdouble offset_x; + gdouble offset_y; + gdouble offset_z; + + if (t3d->updating) + return; + + gimp_matrix4_identity (&matrix); + + gimp_transform_3d_matrix4_rotate_euler (&matrix, + tg_tool->trans_info[ROTATION_ORDER], + tg_tool->trans_info[ANGLE_X], + tg_tool->trans_info[ANGLE_Y], + tg_tool->trans_info[ANGLE_Z], + tg_tool->trans_info[PIVOT_X], + tg_tool->trans_info[PIVOT_Y], + tg_tool->trans_info[PIVOT_Z]); + + gimp_pivot_selector_get_position (GIMP_PIVOT_SELECTOR (t3d->pivot_selector), + &tg_tool->trans_info[PIVOT_X], + &tg_tool->trans_info[PIVOT_Y]); + + gimp_matrix4_transform_point (&matrix, + tg_tool->trans_info[PIVOT_X], + tg_tool->trans_info[PIVOT_Y], + tg_tool->trans_info[PIVOT_Z], + &offset_x, &offset_y, &offset_z); + + tg_tool->trans_info[OFFSET_X] += offset_x - tg_tool->trans_info[PIVOT_X]; + tg_tool->trans_info[OFFSET_Y] += offset_y - tg_tool->trans_info[PIVOT_Y]; + tg_tool->trans_info[OFFSET_Z] += offset_z - tg_tool->trans_info[PIVOT_Z]; + + gimp_transform_grid_tool_push_internal_undo (tg_tool, TRUE); + + gimp_transform_tool_recalc_matrix (tr_tool, tool->display); +} + +static gdouble +gimp_transform_3d_tool_get_focal_length (GimpTransform3DTool *t3d) +{ + GimpTool *tool = GIMP_TOOL (t3d); + GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (t3d); + GimpTransformGridTool *tg_tool = GIMP_TRANSFORM_GRID_TOOL (t3d); + GimpImage *image = gimp_display_get_image (tool->display); + gdouble width = 0.0; + gdouble height = 0.0; + + switch ((int) tg_tool->trans_info[LENS_MODE]) + { + case GIMP_TRANSFORM_3D_LENS_MODE_FOCAL_LENGTH: + return tg_tool->trans_info[LENS_VALUE]; + + case GIMP_TRANSFORM_3D_LENS_MODE_FOV_IMAGE: + width = gimp_image_get_width (image); + height = gimp_image_get_height (image); + break; + + case GIMP_TRANSFORM_3D_LENS_MODE_FOV_ITEM: + width = tr_tool->x2 - tr_tool->x1; + height = tr_tool->y2 - tr_tool->y1; + break; + } + + return gimp_transform_3d_angle_of_view_to_focal_length ( + tg_tool->trans_info[LENS_VALUE], width, height); +} diff --git a/app/tools/gimptransform3dtool.h b/app/tools/gimptransform3dtool.h new file mode 100644 index 0000000000..636befffeb --- /dev/null +++ b/app/tools/gimptransform3dtool.h @@ -0,0 +1,67 @@ +/* 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 . + */ + +#ifndef __GIMP_TRANSFORM_3D_TOOL_H__ +#define __GIMP_TRANSFORM_3D_TOOL_H__ + + +#include "gimptransformgridtool.h" + + +#define GIMP_TYPE_TRANSFORM_3D_TOOL (gimp_transform_3d_tool_get_type ()) +#define GIMP_TRANSFORM_3D_TOOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_TRANSFORM_3D_TOOL, GimpTransform3DTool)) +#define GIMP_TRANSFORM_3D_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_TRANSFORM_3D_TOOL, GimpTransform3DToolClass)) +#define GIMP_IS_TRANSFORM_3D_TOOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_TRANSFORM_3D_TOOL)) +#define GIMP_TRANSFORM_3D_TOOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_TRANSFORM_3D_TOOL, GimpTransform3DToolClass)) + +#define GIMP_TRANSFORM_3D_TOOL_GET_OPTIONS(t) (GIMP_TRANSFORM_3D_OPTIONS (gimp_tool_get_options (GIMP_TOOL (t)))) + + +typedef struct _GimpTransform3DTool GimpTransform3DTool; +typedef struct _GimpTransform3DToolClass GimpTransform3DToolClass; + +struct _GimpTransform3DTool +{ + GimpTransformGridTool parent_instance; + + gboolean updating; + + GtkWidget *notebook; + GtkWidget *vanishing_point_se; + GtkWidget *lens_mode_combo; + GtkWidget *focal_length_se; + GtkWidget *angle_of_view_scale; + GtkAdjustment *angle_of_view_adj; + GtkWidget *offset_se; + GtkWidget *rotation_order_buttons[3]; + GtkAdjustment *angle_adj[3]; + GtkWidget *pivot_selector; +}; + +struct _GimpTransform3DToolClass +{ + GimpTransformGridToolClass parent_class; +}; + + +void gimp_transform_3d_tool_register (GimpToolRegisterCallback callback, + gpointer data); + +GType gimp_transform_3d_tool_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_TRANSFORM_3D_TOOL_H__ */ diff --git a/app/tools/meson.build b/app/tools/meson.build index b4c4bfd530..7e05777657 100644 --- a/app/tools/meson.build +++ b/app/tools/meson.build @@ -115,6 +115,8 @@ libapptools_sources = [ 'gimptoolcontrol.c', 'gimptooloptions-gui.c', 'gimptools-utils.c', + 'gimptransform3doptions.c', + 'gimptransform3dtool.c', 'gimptransformgridoptions.c', 'gimptransformgridtool.c', 'gimptransformgridtoolundo.c', diff --git a/app/tools/tools-enums.c b/app/tools/tools-enums.c index a7afa38a74..5e637e97e0 100644 --- a/app/tools/tools-enums.c +++ b/app/tools/tools-enums.c @@ -261,6 +261,43 @@ gimp_matting_preview_mode_get_type (void) return type; } +GType +gimp_transform_3d_lens_mode_get_type (void) +{ + static const GEnumValue values[] = + { + { GIMP_TRANSFORM_3D_LENS_MODE_FOCAL_LENGTH, "GIMP_TRANSFORM_3D_LENS_MODE_FOCAL_LENGTH", "focal-length" }, + { GIMP_TRANSFORM_3D_LENS_MODE_FOV_IMAGE, "GIMP_TRANSFORM_3D_LENS_MODE_FOV_IMAGE", "fov-image" }, + { GIMP_TRANSFORM_3D_LENS_MODE_FOV_ITEM, "GIMP_TRANSFORM_3D_LENS_MODE_FOV_ITEM", "fov-item" }, + { 0, NULL, NULL } + }; + + static const GimpEnumDesc descs[] = + { + { GIMP_TRANSFORM_3D_LENS_MODE_FOCAL_LENGTH, NC_("3-dtrasnform-lens-mode", "Focal length"), NULL }, + { GIMP_TRANSFORM_3D_LENS_MODE_FOV_IMAGE, NC_("3-dtrasnform-lens-mode", "Field of view (relative to image)"), NULL }, + /* Translators: this is an abbreviated version of "Field of view (relative to image)". + Keep it short. */ + { GIMP_TRANSFORM_3D_LENS_MODE_FOV_IMAGE, NC_("3-dtrasnform-lens-mode", "FOV (image)"), NULL }, + { GIMP_TRANSFORM_3D_LENS_MODE_FOV_ITEM, NC_("3-dtrasnform-lens-mode", "Field of view (relative to item)"), NULL }, + /* Translators: this is an abbreviated version of "Field of view (relative to item)". + Keep it short. */ + { GIMP_TRANSFORM_3D_LENS_MODE_FOV_ITEM, NC_("3-dtrasnform-lens-mode", "FOV (item)"), NULL }, + { 0, NULL, NULL } + }; + + static GType type = 0; + + if (G_UNLIKELY (! type)) + { + type = g_enum_register_static ("Gimp3DTrasnformLensMode", values); + gimp_type_set_translation_context (type, "3-dtrasnform-lens-mode"); + gimp_enum_set_value_descriptions (type, descs); + } + + return type; +} + GType gimp_warp_behavior_get_type (void) { diff --git a/app/tools/tools-enums.h b/app/tools/tools-enums.h index 58d409bdd9..f994bc15bd 100644 --- a/app/tools/tools-enums.h +++ b/app/tools/tools-enums.h @@ -138,6 +138,18 @@ typedef enum } GimpMattingPreviewMode; +#define GIMP_TYPE_TRANSFORM_3D_LENS_MODE (gimp_transform_3d_lens_mode_get_type ()) + +GType gimp_transform_3d_lens_mode_get_type (void) G_GNUC_CONST; + +typedef enum /*< lowercase_name=gimp_transform_3d_lens_mode >*/ +{ + GIMP_TRANSFORM_3D_LENS_MODE_FOCAL_LENGTH, /*< desc="Focal length" >*/ + GIMP_TRANSFORM_3D_LENS_MODE_FOV_IMAGE, /*< desc="Field of view (relative to image)", abbrev="FOV (image)" >*/ + GIMP_TRANSFORM_3D_LENS_MODE_FOV_ITEM, /*< desc="Field of view (relative to item)", abbrev="FOV (item)" >*/ +} Gimp3DTrasnformLensMode; + + #define GIMP_TYPE_WARP_BEHAVIOR (gimp_warp_behavior_get_type ()) GType gimp_warp_behavior_get_type (void) G_GNUC_CONST; diff --git a/icons/Color/16/gimp-tool-transform-3d.png b/icons/Color/16/gimp-tool-transform-3d.png new file mode 100644 index 0000000000..24b0a6591b Binary files /dev/null and b/icons/Color/16/gimp-tool-transform-3d.png differ diff --git a/icons/Color/16/gimp-transform-3d-camera.png b/icons/Color/16/gimp-transform-3d-camera.png new file mode 100644 index 0000000000..cfa519ee52 Binary files /dev/null and b/icons/Color/16/gimp-transform-3d-camera.png differ diff --git a/icons/Color/16/gimp-transform-3d-move.png b/icons/Color/16/gimp-transform-3d-move.png new file mode 100644 index 0000000000..f91733f571 Binary files /dev/null and b/icons/Color/16/gimp-transform-3d-move.png differ diff --git a/icons/Color/16/gimp-transform-3d-rotate.png b/icons/Color/16/gimp-transform-3d-rotate.png new file mode 100644 index 0000000000..f82932c14c Binary files /dev/null and b/icons/Color/16/gimp-transform-3d-rotate.png differ diff --git a/icons/Color/24/gimp-tool-transform-3d.png b/icons/Color/24/gimp-tool-transform-3d.png new file mode 100644 index 0000000000..06d952e15a Binary files /dev/null and b/icons/Color/24/gimp-tool-transform-3d.png differ diff --git a/icons/Color/24/gimp-tool-transform-3d.svg b/icons/Color/24/gimp-tool-transform-3d.svg new file mode 100644 index 0000000000..5881adef4e --- /dev/null +++ b/icons/Color/24/gimp-tool-transform-3d.svg @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/icons/Color/icon-list.mk b/icons/Color/icon-list.mk index 3f4df8b36e..e79b30e5bb 100644 --- a/icons/Color/icon-list.mk +++ b/icons/Color/icon-list.mk @@ -327,9 +327,13 @@ scalable_images = \ scalable/gimp-tools.svg \ scalable/gimp-tool-text.svg \ scalable/gimp-tool-threshold.svg \ + scalable/gimp-tool-transform-3d.svg \ scalable/gimp-tool-unified-transform.svg \ scalable/gimp-tool-warp.svg \ scalable/gimp-tool-zoom.svg \ + scalable/gimp-transform-3d-camera.svg \ + scalable/gimp-transform-3d-move.svg \ + scalable/gimp-transform-3d-rotate.svg \ scalable/gimp-transparency.svg \ scalable/gimp-undo-history.svg \ scalable/gimp-user-manual.svg \ @@ -502,6 +506,7 @@ vector24_images = \ 24/gimp-tool-shear.svg \ 24/gimp-tool-smudge.svg \ 24/gimp-tool-threshold.svg \ + 24/gimp-tool-transform-3d.svg \ 24/gimp-tool-unified-transform.svg \ 24/gimp-tool-text.svg \ 24/gimp-tool-warp.svg \ @@ -801,11 +806,15 @@ icons16_images = \ 16/gimp-tool-smudge.png \ 16/gimp-tool-text.png \ 16/gimp-tool-threshold.png \ + 16/gimp-tool-transform-3d.png \ 16/gimp-tool-unified-transform.png \ 16/gimp-tool-warp.png \ 16/gimp-tool-zoom.png \ 16/gimp-tools.png \ 16/gimp-transparency.png \ + 16/gimp-transform-3d-camera.svg \ + 16/gimp-transform-3d-move.svg \ + 16/gimp-transform-3d-rotate.svg \ 16/gimp-undo-history.png \ 16/gimp-user-manual.png \ 16/gimp-video.png \ @@ -1012,6 +1021,7 @@ icons24_images = \ 24/gimp-tool-smudge.png \ 24/gimp-tool-text.png \ 24/gimp-tool-threshold.png \ + 24/gimp-tool-transform-3d.png \ 24/gimp-tool-unified-transform.png \ 24/gimp-tool-warp.png \ 24/gimp-tool-zoom.png \ diff --git a/icons/Color/scalable/gimp-tool-transform-3d.svg b/icons/Color/scalable/gimp-tool-transform-3d.svg new file mode 100644 index 0000000000..30ad31c216 --- /dev/null +++ b/icons/Color/scalable/gimp-tool-transform-3d.svg @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/icons/Color/scalable/gimp-transform-3d-camera.svg b/icons/Color/scalable/gimp-transform-3d-camera.svg new file mode 100644 index 0000000000..c819c36aee --- /dev/null +++ b/icons/Color/scalable/gimp-transform-3d-camera.svg @@ -0,0 +1,68 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/icons/Color/scalable/gimp-transform-3d-move.svg b/icons/Color/scalable/gimp-transform-3d-move.svg new file mode 100644 index 0000000000..e5bdac4c23 --- /dev/null +++ b/icons/Color/scalable/gimp-transform-3d-move.svg @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/icons/Color/scalable/gimp-transform-3d-rotate.svg b/icons/Color/scalable/gimp-transform-3d-rotate.svg new file mode 100644 index 0000000000..8c0d2f3586 --- /dev/null +++ b/icons/Color/scalable/gimp-transform-3d-rotate.svg @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/icons/Symbolic/24/gimp-tool-transform-3d-symbolic.svg b/icons/Symbolic/24/gimp-tool-transform-3d-symbolic.svg new file mode 100644 index 0000000000..c983032cc4 --- /dev/null +++ b/icons/Symbolic/24/gimp-tool-transform-3d-symbolic.svg @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/icons/Symbolic/icon-list.mk b/icons/Symbolic/icon-list.mk index 36f4fda37a..4930fd8618 100644 --- a/icons/Symbolic/icon-list.mk +++ b/icons/Symbolic/icon-list.mk @@ -323,9 +323,13 @@ scalable_images = \ scalable/gimp-tools-symbolic.svg \ scalable/gimp-tool-text-symbolic.svg \ scalable/gimp-tool-threshold-symbolic.svg \ + scalable/gimp-tool-transform-3d-symbolic.svg \ scalable/gimp-tool-unified-transform-symbolic.svg \ scalable/gimp-tool-warp-symbolic.svg \ scalable/gimp-tool-zoom-symbolic.svg \ + scalable/gimp-transform-3d-camera-symbolic.svg \ + scalable/gimp-transform-3d-move-symbolic.svg \ + scalable/gimp-transform-3d-rotate-symbolic.svg \ scalable/gimp-transparency-symbolic.svg \ scalable/gimp-undo-history-symbolic.svg \ scalable/gimp-user-manual-symbolic.svg \ @@ -498,6 +502,7 @@ vector24_images = \ 24/gimp-tool-shear-symbolic.svg \ 24/gimp-tool-smudge-symbolic.svg \ 24/gimp-tool-threshold-symbolic.svg \ + 24/gimp-tool-transform-3d-symbolic.svg \ 24/gimp-tool-unified-transform-symbolic.svg \ 24/gimp-tool-text-symbolic.svg \ 24/gimp-tool-warp-symbolic.svg \ @@ -793,10 +798,14 @@ icons16_images = \ 16/gimp-tool-smudge-symbolic.symbolic.png \ 16/gimp-tool-text-symbolic.symbolic.png \ 16/gimp-tool-threshold-symbolic.symbolic.png \ + 16/gimp-tool-transform-3d-symbolic.symbolic.png \ 16/gimp-tool-unified-transform-symbolic.symbolic.png \ 16/gimp-tool-warp-symbolic.symbolic.png \ 16/gimp-tool-zoom-symbolic.symbolic.png \ 16/gimp-tools-symbolic.symbolic.png \ + 16/gimp-transform-3d-camera-symbolic.symbolic.png \ + 16/gimp-transform-3d-move-symbolic.symbolic.png \ + 16/gimp-transform-3d-rotate-symbolic.symbolic.png \ 16/gimp-transparency-symbolic.symbolic.png \ 16/gimp-undo-history-symbolic.symbolic.png \ 16/gimp-user-manual-symbolic.symbolic.png \ @@ -1004,6 +1013,7 @@ icons24_images = \ 24/gimp-tool-smudge-symbolic.symbolic.png \ 24/gimp-tool-text-symbolic.symbolic.png \ 24/gimp-tool-threshold-symbolic.symbolic.png \ + 24/gimp-tool-transform-3d-symbolic.symbolic.png \ 24/gimp-tool-unified-transform-symbolic.symbolic.png \ 24/gimp-tool-warp-symbolic.symbolic.png \ 24/gimp-tool-zoom-symbolic.symbolic.png \ diff --git a/icons/Symbolic/scalable/gimp-tool-transform-3d-symbolic.svg b/icons/Symbolic/scalable/gimp-tool-transform-3d-symbolic.svg new file mode 100644 index 0000000000..f1b47e5db4 --- /dev/null +++ b/icons/Symbolic/scalable/gimp-tool-transform-3d-symbolic.svg @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/icons/Symbolic/scalable/gimp-transform-3d-camera-symbolic.svg b/icons/Symbolic/scalable/gimp-transform-3d-camera-symbolic.svg new file mode 100644 index 0000000000..bd02242233 --- /dev/null +++ b/icons/Symbolic/scalable/gimp-transform-3d-camera-symbolic.svg @@ -0,0 +1,79 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/icons/Symbolic/scalable/gimp-transform-3d-move-symbolic.svg b/icons/Symbolic/scalable/gimp-transform-3d-move-symbolic.svg new file mode 100644 index 0000000000..69697c4f1c --- /dev/null +++ b/icons/Symbolic/scalable/gimp-transform-3d-move-symbolic.svg @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/icons/Symbolic/scalable/gimp-transform-3d-rotate-symbolic.svg b/icons/Symbolic/scalable/gimp-transform-3d-rotate-symbolic.svg new file mode 100644 index 0000000000..1d08b86e01 --- /dev/null +++ b/icons/Symbolic/scalable/gimp-transform-3d-rotate-symbolic.svg @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/libgimpwidgets/gimpicons.h b/libgimpwidgets/gimpicons.h index 546f40151a..e47fb7acc5 100644 --- a/libgimpwidgets/gimpicons.h +++ b/libgimpwidgets/gimpicons.h @@ -388,10 +388,15 @@ G_BEGIN_DECLS #define GIMP_ICON_TOOL_SMUDGE "gimp-tool-smudge" #define GIMP_ICON_TOOL_TEXT "gimp-tool-text" #define GIMP_ICON_TOOL_THRESHOLD "gimp-tool-threshold" +#define GIMP_ICON_TOOL_TRANSFORM_3D "gimp-tool-transform-3d" #define GIMP_ICON_TOOL_UNIFIED_TRANSFORM "gimp-tool-unified-transform" #define GIMP_ICON_TOOL_WARP "gimp-tool-warp" #define GIMP_ICON_TOOL_ZOOM "gimp-tool-zoom" +#define GIMP_ICON_TRANSFORM_3D_CAMERA "gimp-transform-3d-camera" +#define GIMP_ICON_TRANSFORM_3D_MOVE "gimp-transform-3d-move" +#define GIMP_ICON_TRANSFORM_3D_ROTATE "gimp-transform-3d-rotate" + #define GIMP_ICON_VIEW_REFRESH "view-refresh" #define GIMP_ICON_VIEW_FULLSCREEN "view-fullscreen" diff --git a/po/POTFILES.in b/po/POTFILES.in index 8faa5b2cbc..33dfd07a7e 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -502,6 +502,8 @@ app/tools/gimptool.c app/tools/gimptooloptions-gui.c app/tools/gimptransformgridoptions.c app/tools/gimptransformgridtool.c +app/tools/gimptransform3doptions.c +app/tools/gimptransform3dtool.c app/tools/gimptransformoptions.c app/tools/gimptransformtool.c app/tools/gimpunifiedtransformtool.c