As reported by Liam, apparently for someone with a lot of filters, these node creations just to check the aux input may add up noticeable time on boot (it may also depend on the OS too? I didn't have any noticeable delay personally). Unfortunately we cannot know the presence of an aux input just with class introspection because they can be registered by the op at runtime. This optimization is therefore twofold: * Since we know which filters have an aux input among all the ones with hardcoded actions, we also hardcode this data. It means we only do the actual check on non-hardcoded operations (third-party filters but also GEGL operations which are not specifically listed in our code). * I only do these checks once, stored by name in a hash table, because filters_actions_setup() is actually run several times (for different menus). This should improve startup time a lot for people who experienced this delay.
877 lines
24 KiB
C
877 lines
24 KiB
C
/* 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 "libgimpwidgets/gimpwidgets.h"
|
|
|
|
#include "actions-types.h"
|
|
|
|
#include "core/gimp.h"
|
|
#include "core/gimpcontainer.h"
|
|
#include "core/gimpcontext.h"
|
|
#include "core/gimpimage.h"
|
|
#include "core/gimpitem.h"
|
|
#include "core/gimptooloptions.h"
|
|
#include "core/gimptoolinfo.h"
|
|
|
|
#include "widgets/gimpactionfactory.h"
|
|
#include "widgets/gimpactiongroup.h"
|
|
#include "widgets/gimpcontainereditor.h"
|
|
#include "widgets/gimpcontainerview.h"
|
|
#include "widgets/gimpdock.h"
|
|
#include "widgets/gimpdockable.h"
|
|
#include "widgets/gimpdockwindow.h"
|
|
#include "widgets/gimpimageeditor.h"
|
|
#include "widgets/gimpitemtreeview.h"
|
|
|
|
#include "display/gimpdisplay.h"
|
|
#include "display/gimpdisplayshell.h"
|
|
#include "display/gimpimagewindow.h"
|
|
#include "display/gimpnavigationeditor.h"
|
|
#include "display/gimpstatusbar.h"
|
|
|
|
#include "dialogs/dialogs.h"
|
|
|
|
#include "actions.h"
|
|
#include "brush-editor-actions.h"
|
|
#include "brushes-actions.h"
|
|
#include "buffers-actions.h"
|
|
#include "channels-actions.h"
|
|
#include "colormap-actions.h"
|
|
#include "context-actions.h"
|
|
#include "cursor-info-actions.h"
|
|
#include "dashboard-actions.h"
|
|
#include "debug-actions.h"
|
|
#include "dialogs-actions.h"
|
|
#include "dock-actions.h"
|
|
#include "dockable-actions.h"
|
|
#include "documents-actions.h"
|
|
#include "drawable-actions.h"
|
|
#include "dynamics-actions.h"
|
|
#include "dynamics-editor-actions.h"
|
|
#include "edit-actions.h"
|
|
#include "error-console-actions.h"
|
|
#include "file-actions.h"
|
|
#include "filters-actions.h"
|
|
#include "fonts-actions.h"
|
|
#include "gradient-editor-actions.h"
|
|
#include "gradients-actions.h"
|
|
#include "help-actions.h"
|
|
#include "image-actions.h"
|
|
#include "images-actions.h"
|
|
#include "layers-actions.h"
|
|
#include "mypaint-brushes-actions.h"
|
|
#include "palette-editor-actions.h"
|
|
#include "palettes-actions.h"
|
|
#include "paths-actions.h"
|
|
#include "patterns-actions.h"
|
|
#include "plug-in-actions.h"
|
|
#include "quick-mask-actions.h"
|
|
#include "sample-points-actions.h"
|
|
#include "select-actions.h"
|
|
#include "templates-actions.h"
|
|
#include "text-editor-actions.h"
|
|
#include "text-tool-actions.h"
|
|
#include "tool-options-actions.h"
|
|
#include "tool-path-actions.h"
|
|
#include "tool-presets-actions.h"
|
|
#include "tool-preset-editor-actions.h"
|
|
#include "tools-actions.h"
|
|
#include "view-actions.h"
|
|
#include "windows-actions.h"
|
|
|
|
#include "gimp-intl.h"
|
|
|
|
|
|
/* global variables */
|
|
|
|
GimpActionFactory *global_action_factory = NULL;
|
|
GHashTable *aux_filter_hash_table = NULL;
|
|
|
|
|
|
/* private variables */
|
|
|
|
static const GimpActionFactoryEntry action_groups[] =
|
|
{
|
|
{ "brush-editor", N_("Brush Editor"), GIMP_ICON_BRUSH,
|
|
brush_editor_actions_setup,
|
|
brush_editor_actions_update },
|
|
{ "brushes", N_("Brushes"), GIMP_ICON_BRUSH,
|
|
brushes_actions_setup,
|
|
brushes_actions_update },
|
|
{ "buffers", N_("Buffers"), GIMP_ICON_BUFFER,
|
|
buffers_actions_setup,
|
|
buffers_actions_update },
|
|
{ "channels", N_("Channels"), GIMP_ICON_CHANNEL,
|
|
channels_actions_setup,
|
|
channels_actions_update },
|
|
{ "colormap", N_("Colormap"), GIMP_ICON_COLORMAP,
|
|
colormap_actions_setup,
|
|
colormap_actions_update },
|
|
{ "context", N_("Context"), GIMP_ICON_DIALOG_TOOL_OPTIONS /* well... */,
|
|
context_actions_setup,
|
|
context_actions_update },
|
|
{ "cursor-info", N_("Pointer Information"), NULL,
|
|
cursor_info_actions_setup,
|
|
cursor_info_actions_update },
|
|
{ "dashboard", N_("Dashboard"), GIMP_ICON_DIALOG_DASHBOARD,
|
|
dashboard_actions_setup,
|
|
dashboard_actions_update },
|
|
{ "debug", N_("Debug"), NULL,
|
|
debug_actions_setup,
|
|
debug_actions_update },
|
|
{ "dialogs", N_("Dialogs"), NULL,
|
|
dialogs_actions_setup,
|
|
dialogs_actions_update },
|
|
{ "dock", N_("Dock"), NULL,
|
|
dock_actions_setup,
|
|
dock_actions_update },
|
|
{ "dockable", N_("Dockable"), NULL,
|
|
dockable_actions_setup,
|
|
dockable_actions_update },
|
|
{ "documents", N_("Document History"), NULL,
|
|
documents_actions_setup,
|
|
documents_actions_update },
|
|
{ "drawable", N_("Drawable"), GIMP_ICON_LAYER,
|
|
drawable_actions_setup,
|
|
drawable_actions_update },
|
|
{ "dynamics", N_("Paint Dynamics"), GIMP_ICON_DYNAMICS,
|
|
dynamics_actions_setup,
|
|
dynamics_actions_update },
|
|
{ "dynamics-editor", N_("Paint Dynamics Editor"), GIMP_ICON_DYNAMICS,
|
|
dynamics_editor_actions_setup,
|
|
dynamics_editor_actions_update },
|
|
{ "edit", N_("Edit"), GIMP_ICON_EDIT,
|
|
edit_actions_setup,
|
|
edit_actions_update },
|
|
{ "error-console", N_("Error Console"), GIMP_ICON_DIALOG_WARNING,
|
|
error_console_actions_setup,
|
|
error_console_actions_update },
|
|
{ "file", N_("File"), "text-x-generic",
|
|
file_actions_setup,
|
|
file_actions_update },
|
|
{ "filters", N_("Filters"), GIMP_ICON_GEGL,
|
|
filters_actions_setup,
|
|
filters_actions_update },
|
|
{ "fonts", N_("Fonts"), GIMP_ICON_FONT,
|
|
fonts_actions_setup,
|
|
fonts_actions_update },
|
|
{ "gradient-editor", N_("Gradient Editor"), GIMP_ICON_GRADIENT,
|
|
gradient_editor_actions_setup,
|
|
gradient_editor_actions_update },
|
|
{ "gradients", N_("Gradients"), GIMP_ICON_GRADIENT,
|
|
gradients_actions_setup,
|
|
gradients_actions_update },
|
|
{ "tool-presets", N_("Tool Presets"), GIMP_ICON_TOOL_PRESET,
|
|
tool_presets_actions_setup,
|
|
tool_presets_actions_update },
|
|
{ "tool-preset-editor", N_("Tool Preset Editor"), GIMP_ICON_TOOL_PRESET,
|
|
tool_preset_editor_actions_setup,
|
|
tool_preset_editor_actions_update },
|
|
{ "help", N_("Help"), "help-browser",
|
|
help_actions_setup,
|
|
help_actions_update },
|
|
{ "image", N_("Image"), GIMP_ICON_IMAGE,
|
|
image_actions_setup,
|
|
image_actions_update },
|
|
{ "images", N_("Images"), GIMP_ICON_IMAGE,
|
|
images_actions_setup,
|
|
images_actions_update },
|
|
{ "layers", N_("Layers"), GIMP_ICON_LAYER,
|
|
layers_actions_setup,
|
|
layers_actions_update },
|
|
{ "mypaint-brushes", N_("MyPaint Brushes"), GIMP_ICON_MYPAINT_BRUSH,
|
|
mypaint_brushes_actions_setup,
|
|
mypaint_brushes_actions_update },
|
|
{ "palette-editor", N_("Palette Editor"), GIMP_ICON_PALETTE,
|
|
palette_editor_actions_setup,
|
|
palette_editor_actions_update },
|
|
{ "palettes", N_("Palettes"), GIMP_ICON_PALETTE,
|
|
palettes_actions_setup,
|
|
palettes_actions_update },
|
|
{ "patterns", N_("Patterns"), GIMP_ICON_PATTERN,
|
|
patterns_actions_setup,
|
|
patterns_actions_update },
|
|
{ "plug-in", N_("Plug-ins"), GIMP_ICON_PLUGIN,
|
|
plug_in_actions_setup,
|
|
plug_in_actions_update },
|
|
{ "quick-mask", N_("Quick Mask"), GIMP_ICON_QUICK_MASK_ON,
|
|
quick_mask_actions_setup,
|
|
quick_mask_actions_update },
|
|
{ "sample-points", N_("Sample Points"), GIMP_ICON_SAMPLE_POINT,
|
|
sample_points_actions_setup,
|
|
sample_points_actions_update },
|
|
{ "select", N_("Select"), GIMP_ICON_SELECTION,
|
|
select_actions_setup,
|
|
select_actions_update },
|
|
{ "templates", N_("Templates"), GIMP_ICON_TEMPLATE,
|
|
templates_actions_setup,
|
|
templates_actions_update },
|
|
{ "text-tool", N_("Text Tool"), GIMP_ICON_EDIT,
|
|
text_tool_actions_setup,
|
|
text_tool_actions_update },
|
|
{ "text-editor", N_("Text Editor"), GIMP_ICON_EDIT,
|
|
text_editor_actions_setup,
|
|
text_editor_actions_update },
|
|
{ "tool-options", N_("Tool Options"), GIMP_ICON_DIALOG_TOOL_OPTIONS,
|
|
tool_options_actions_setup,
|
|
tool_options_actions_update },
|
|
{ "tool-path", N_("Tool Path"), GIMP_ICON_PATH,
|
|
tool_path_actions_setup,
|
|
tool_path_actions_update },
|
|
{ "tools", N_("Tools"), GIMP_ICON_DIALOG_TOOLS,
|
|
tools_actions_setup,
|
|
tools_actions_update },
|
|
{ "paths", N_("Paths"), GIMP_ICON_PATH,
|
|
paths_actions_setup,
|
|
paths_actions_update },
|
|
{ "view", N_("View"), GIMP_ICON_VISIBLE,
|
|
view_actions_setup,
|
|
view_actions_update },
|
|
{ "windows", N_("Windows"), NULL,
|
|
windows_actions_setup,
|
|
windows_actions_update }
|
|
};
|
|
|
|
|
|
/* public functions */
|
|
|
|
void
|
|
actions_init (Gimp *gimp)
|
|
{
|
|
gint i;
|
|
|
|
g_return_if_fail (GIMP_IS_GIMP (gimp));
|
|
g_return_if_fail (global_action_factory == NULL);
|
|
|
|
global_action_factory = gimp_action_factory_new (gimp);
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (action_groups); i++)
|
|
gimp_action_factory_group_register (global_action_factory,
|
|
action_groups[i].identifier,
|
|
gettext (action_groups[i].label),
|
|
action_groups[i].icon_name,
|
|
action_groups[i].setup_func,
|
|
action_groups[i].update_func);
|
|
|
|
aux_filter_hash_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
|
}
|
|
|
|
void
|
|
actions_exit (Gimp *gimp)
|
|
{
|
|
g_return_if_fail (GIMP_IS_GIMP (gimp));
|
|
g_return_if_fail (global_action_factory != NULL);
|
|
g_return_if_fail (global_action_factory->gimp == gimp);
|
|
|
|
g_clear_object (&global_action_factory);
|
|
g_hash_table_unref (aux_filter_hash_table);
|
|
}
|
|
|
|
/* XXX Temporary code to store the list of filter operations with an
|
|
* "aux" input. This won't be necessary anymore once these filters can
|
|
* be applied non-destructively too in the future.
|
|
*/
|
|
void
|
|
actions_filter_set_aux (const gchar *action_name)
|
|
{
|
|
g_hash_table_add (aux_filter_hash_table, (gpointer) g_strdup (action_name));
|
|
}
|
|
|
|
gboolean
|
|
actions_filter_get_aux (const gchar *action_name)
|
|
{
|
|
return g_hash_table_lookup (aux_filter_hash_table, action_name) != NULL;
|
|
}
|
|
|
|
Gimp *
|
|
action_data_get_gimp (gpointer data)
|
|
{
|
|
Gimp *result = NULL;
|
|
static gboolean recursion = FALSE;
|
|
|
|
if (! data || recursion)
|
|
return NULL;
|
|
|
|
recursion = TRUE;
|
|
|
|
if (GIMP_IS_GIMP (data))
|
|
result = data;
|
|
|
|
if (! result)
|
|
{
|
|
GimpDisplay *display = action_data_get_display (data);
|
|
|
|
if (display)
|
|
result = display->gimp;
|
|
}
|
|
|
|
if (! result)
|
|
{
|
|
GimpContext *context = action_data_get_context (data);
|
|
|
|
if (context)
|
|
result = context->gimp;
|
|
}
|
|
|
|
recursion = FALSE;
|
|
|
|
return result;
|
|
}
|
|
|
|
GimpContext *
|
|
action_data_get_context (gpointer data)
|
|
{
|
|
GimpContext *result = NULL;
|
|
static gboolean recursion = FALSE;
|
|
|
|
if (! data || recursion)
|
|
return NULL;
|
|
|
|
recursion = TRUE;
|
|
|
|
if (GIMP_IS_DOCK (data))
|
|
result = gimp_dock_get_context ((GimpDock *) data);
|
|
else if (GIMP_IS_DOCK_WINDOW (data))
|
|
result = gimp_dock_window_get_context (((GimpDockWindow *) data));
|
|
else if (GIMP_IS_CONTAINER_VIEW (data))
|
|
result = gimp_container_view_get_context ((GimpContainerView *) data);
|
|
else if (GIMP_IS_CONTAINER_EDITOR (data))
|
|
result = gimp_container_view_get_context (((GimpContainerEditor *) data)->view);
|
|
else if (GIMP_IS_IMAGE_EDITOR (data))
|
|
result = ((GimpImageEditor *) data)->context;
|
|
else if (GIMP_IS_NAVIGATION_EDITOR (data))
|
|
result = ((GimpNavigationEditor *) data)->context;
|
|
|
|
if (! result)
|
|
{
|
|
Gimp *gimp = action_data_get_gimp (data);
|
|
|
|
if (gimp)
|
|
result = gimp_get_user_context (gimp);
|
|
}
|
|
|
|
recursion = FALSE;
|
|
|
|
return result;
|
|
}
|
|
|
|
GimpImage *
|
|
action_data_get_image (gpointer data)
|
|
{
|
|
GimpImage *result = NULL;
|
|
static gboolean recursion = FALSE;
|
|
|
|
if (! data || recursion)
|
|
return NULL;
|
|
|
|
recursion = TRUE;
|
|
|
|
if (GIMP_IS_ITEM_TREE_VIEW (data))
|
|
{
|
|
result = gimp_item_tree_view_get_image ((GimpItemTreeView *) data);
|
|
recursion = FALSE;
|
|
return result;
|
|
}
|
|
else if (GIMP_IS_IMAGE_EDITOR (data))
|
|
{
|
|
result = ((GimpImageEditor *) data)->image;
|
|
recursion = FALSE;
|
|
return result;
|
|
}
|
|
|
|
if (! result)
|
|
{
|
|
GimpDisplay *display = action_data_get_display (data);
|
|
|
|
if (display)
|
|
result = gimp_display_get_image (display);
|
|
}
|
|
|
|
if (! result)
|
|
{
|
|
GimpContext *context = action_data_get_context (data);
|
|
|
|
if (context)
|
|
result = gimp_context_get_image (context);
|
|
}
|
|
|
|
recursion = FALSE;
|
|
|
|
return result;
|
|
}
|
|
|
|
GimpDisplay *
|
|
action_data_get_display (gpointer data)
|
|
{
|
|
GimpDisplay *result = NULL;
|
|
static gboolean recursion = FALSE;
|
|
|
|
if (! data || recursion)
|
|
return NULL;
|
|
|
|
recursion = TRUE;
|
|
|
|
if (GIMP_IS_DISPLAY (data))
|
|
result = data;
|
|
else if (GIMP_IS_IMAGE_WINDOW (data))
|
|
{
|
|
GimpDisplayShell *shell = gimp_image_window_get_active_shell (data);
|
|
result = shell ? shell->display : NULL;
|
|
}
|
|
|
|
if (! result)
|
|
{
|
|
GimpContext *context = action_data_get_context (data);
|
|
|
|
if (context)
|
|
result = gimp_context_get_display (context);
|
|
}
|
|
|
|
recursion = FALSE;
|
|
|
|
return result;
|
|
}
|
|
|
|
GimpDisplayShell *
|
|
action_data_get_shell (gpointer data)
|
|
{
|
|
GimpDisplayShell *result = NULL;
|
|
static gboolean recursion = FALSE;
|
|
|
|
if (! data || recursion)
|
|
return NULL;
|
|
|
|
recursion = TRUE;
|
|
|
|
if (! result)
|
|
{
|
|
GimpDisplay *display = action_data_get_display (data);
|
|
|
|
if (display)
|
|
result = gimp_display_get_shell (display);
|
|
}
|
|
|
|
recursion = FALSE;
|
|
|
|
return result;
|
|
}
|
|
|
|
GtkWidget *
|
|
action_data_get_widget (gpointer data)
|
|
{
|
|
GtkWidget *result = NULL;
|
|
static gboolean recursion = FALSE;
|
|
|
|
if (! data || recursion)
|
|
return NULL;
|
|
|
|
recursion = TRUE;
|
|
|
|
if (GTK_IS_WIDGET (data))
|
|
result = data;
|
|
|
|
if (! result)
|
|
{
|
|
GimpDisplay *display = action_data_get_display (data);
|
|
|
|
if (display)
|
|
result = GTK_WIDGET (gimp_display_get_shell (display));
|
|
}
|
|
|
|
if (! result)
|
|
result = dialogs_get_toolbox ();
|
|
|
|
recursion = FALSE;
|
|
|
|
return result;
|
|
}
|
|
|
|
gint
|
|
action_data_sel_count (gpointer data)
|
|
{
|
|
if (GIMP_IS_CONTAINER_EDITOR (data))
|
|
{
|
|
GimpContainerEditor *editor = GIMP_CONTAINER_EDITOR (data);
|
|
|
|
return gimp_container_view_get_selected (editor->view, NULL);
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* action_select_value:
|
|
* @select_type:
|
|
* @value:
|
|
* @min:
|
|
* max:
|
|
* def:
|
|
* small_inc:
|
|
* inc:
|
|
* skip_inc:
|
|
* delta_factor:
|
|
* wrap:
|
|
*
|
|
* For any valid enum @value (which are all negative), the corresponding
|
|
* action computes the semantic value (default, first, next, etc.).
|
|
* For a positive @value, it is considered as a per-thousand value
|
|
* between the @min and @max (possibly wrapped if @wrap is set, clamped
|
|
* otherwise), allowing to compute the returned value.
|
|
*
|
|
* Returns: the computed value to use for the action.
|
|
*/
|
|
gdouble
|
|
action_select_value (GimpActionSelectType select_type,
|
|
gdouble value,
|
|
gdouble min,
|
|
gdouble max,
|
|
gdouble def,
|
|
gdouble small_inc,
|
|
gdouble inc,
|
|
gdouble skip_inc,
|
|
gdouble delta_factor,
|
|
gboolean wrap)
|
|
{
|
|
switch (select_type)
|
|
{
|
|
case GIMP_ACTION_SELECT_SET_TO_DEFAULT:
|
|
value = def;
|
|
break;
|
|
|
|
case GIMP_ACTION_SELECT_FIRST:
|
|
value = min;
|
|
break;
|
|
|
|
case GIMP_ACTION_SELECT_LAST:
|
|
value = max;
|
|
break;
|
|
|
|
case GIMP_ACTION_SELECT_SMALL_PREVIOUS:
|
|
value -= small_inc;
|
|
break;
|
|
|
|
case GIMP_ACTION_SELECT_SMALL_NEXT:
|
|
value += small_inc;
|
|
break;
|
|
|
|
case GIMP_ACTION_SELECT_PREVIOUS:
|
|
value -= inc;
|
|
break;
|
|
|
|
case GIMP_ACTION_SELECT_NEXT:
|
|
value += inc;
|
|
break;
|
|
|
|
case GIMP_ACTION_SELECT_SKIP_PREVIOUS:
|
|
value -= skip_inc;
|
|
break;
|
|
|
|
case GIMP_ACTION_SELECT_SKIP_NEXT:
|
|
value += skip_inc;
|
|
break;
|
|
|
|
case GIMP_ACTION_SELECT_PERCENT_PREVIOUS:
|
|
g_return_val_if_fail (delta_factor >= 0.0, value);
|
|
value /= (1.0 + delta_factor);
|
|
break;
|
|
|
|
case GIMP_ACTION_SELECT_PERCENT_NEXT:
|
|
g_return_val_if_fail (delta_factor >= 0.0, value);
|
|
value *= (1.0 + delta_factor);
|
|
break;
|
|
|
|
default:
|
|
if ((gint) select_type >= 0)
|
|
value = (gdouble) select_type * (max - min) / 1000.0 + min;
|
|
else
|
|
g_return_val_if_reached (value);
|
|
break;
|
|
}
|
|
|
|
if (wrap)
|
|
{
|
|
while (value < min)
|
|
value = max - (min - value);
|
|
|
|
while (value > max)
|
|
value = min + (value - max);
|
|
}
|
|
else
|
|
{
|
|
value = CLAMP (value, min, max);
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
void
|
|
action_select_property (GimpActionSelectType select_type,
|
|
GimpDisplay *display,
|
|
GObject *object,
|
|
const gchar *property_name,
|
|
gdouble small_inc,
|
|
gdouble inc,
|
|
gdouble skip_inc,
|
|
gdouble delta_factor,
|
|
gboolean wrap)
|
|
{
|
|
GParamSpec *pspec;
|
|
|
|
g_return_if_fail (display == NULL || GIMP_IS_DISPLAY (display));
|
|
g_return_if_fail (G_IS_OBJECT (object));
|
|
g_return_if_fail (property_name != NULL);
|
|
|
|
pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object),
|
|
property_name);
|
|
|
|
if (G_IS_PARAM_SPEC_DOUBLE (pspec))
|
|
{
|
|
gdouble value;
|
|
|
|
g_object_get (object, property_name, &value, NULL);
|
|
|
|
value = action_select_value (select_type,
|
|
value,
|
|
G_PARAM_SPEC_DOUBLE (pspec)->minimum,
|
|
G_PARAM_SPEC_DOUBLE (pspec)->maximum,
|
|
G_PARAM_SPEC_DOUBLE (pspec)->default_value,
|
|
small_inc, inc, skip_inc, delta_factor, wrap);
|
|
|
|
g_object_set (object, property_name, value, NULL);
|
|
|
|
if (display)
|
|
{
|
|
const gchar *blurb = g_param_spec_get_blurb (pspec);
|
|
|
|
if (blurb)
|
|
{
|
|
/* value description and new value shown in the status bar */
|
|
action_message (display, object, _("%s: %.2f"), blurb, value);
|
|
}
|
|
}
|
|
}
|
|
else if (G_IS_PARAM_SPEC_INT (pspec))
|
|
{
|
|
gint value;
|
|
|
|
g_object_get (object, property_name, &value, NULL);
|
|
|
|
value = action_select_value (select_type,
|
|
value,
|
|
G_PARAM_SPEC_INT (pspec)->minimum,
|
|
G_PARAM_SPEC_INT (pspec)->maximum,
|
|
G_PARAM_SPEC_INT (pspec)->default_value,
|
|
small_inc, inc, skip_inc, delta_factor, wrap);
|
|
|
|
g_object_set (object, property_name, value, NULL);
|
|
|
|
if (display)
|
|
{
|
|
const gchar *blurb = g_param_spec_get_blurb (pspec);
|
|
|
|
if (blurb)
|
|
{
|
|
/* value description and new value shown in the status bar */
|
|
action_message (display, object, _("%s: %d"), blurb, value);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
g_return_if_reached ();
|
|
}
|
|
}
|
|
|
|
GimpObject *
|
|
action_select_object (GimpActionSelectType select_type,
|
|
GimpContainer *container,
|
|
GimpObject *current)
|
|
{
|
|
gint select_index;
|
|
gint n_children;
|
|
|
|
g_return_val_if_fail (GIMP_IS_CONTAINER (container), NULL);
|
|
g_return_val_if_fail (current == NULL || GIMP_IS_OBJECT (current), NULL);
|
|
|
|
if (! current &&
|
|
select_type != GIMP_ACTION_SELECT_FIRST &&
|
|
select_type != GIMP_ACTION_SELECT_LAST)
|
|
return NULL;
|
|
|
|
n_children = gimp_container_get_n_children (container);
|
|
|
|
if (n_children == 0)
|
|
return NULL;
|
|
|
|
switch (select_type)
|
|
{
|
|
case GIMP_ACTION_SELECT_FIRST:
|
|
select_index = 0;
|
|
break;
|
|
|
|
case GIMP_ACTION_SELECT_LAST:
|
|
select_index = n_children - 1;
|
|
break;
|
|
|
|
case GIMP_ACTION_SELECT_PREVIOUS:
|
|
select_index = gimp_container_get_child_index (container, current) - 1;
|
|
break;
|
|
|
|
case GIMP_ACTION_SELECT_NEXT:
|
|
select_index = gimp_container_get_child_index (container, current) + 1;
|
|
break;
|
|
|
|
case GIMP_ACTION_SELECT_SKIP_PREVIOUS:
|
|
select_index = gimp_container_get_child_index (container, current) - 10;
|
|
break;
|
|
|
|
case GIMP_ACTION_SELECT_SKIP_NEXT:
|
|
select_index = gimp_container_get_child_index (container, current) + 10;
|
|
break;
|
|
|
|
case GIMP_ACTION_SELECT_FLAT_PREVIOUS:
|
|
/* XXX We only support this case and the next for GimpItem
|
|
* containers.
|
|
*/
|
|
g_return_val_if_fail (GIMP_IS_ITEM (current), NULL);
|
|
select_index = gimp_container_get_child_index (container, current) - 1;
|
|
if (select_index < 0)
|
|
{
|
|
GimpItem *parent = gimp_item_get_parent (GIMP_ITEM (current));
|
|
|
|
if (parent)
|
|
return GIMP_OBJECT (parent);
|
|
else
|
|
return current;
|
|
}
|
|
else
|
|
{
|
|
GimpObject *prev;
|
|
GimpContainer *prev_container;
|
|
|
|
prev = gimp_container_get_child_by_index (container, select_index);
|
|
while ((prev_container = gimp_viewable_get_children (GIMP_VIEWABLE (prev))) != NULL)
|
|
{
|
|
if (gimp_viewable_get_expanded (GIMP_VIEWABLE (prev)))
|
|
{
|
|
gint n_prev_children;
|
|
|
|
n_prev_children = gimp_container_get_n_children (prev_container);
|
|
if (n_prev_children > 0)
|
|
{
|
|
select_index = n_prev_children - 1;
|
|
container = prev_container;
|
|
prev = gimp_container_get_child_by_index (container, select_index);
|
|
continue;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case GIMP_ACTION_SELECT_FLAT_NEXT:
|
|
{
|
|
GimpContainer *current_container;
|
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (current), NULL);
|
|
|
|
if ((current_container = gimp_viewable_get_children (GIMP_VIEWABLE (current))) != NULL &&
|
|
gimp_viewable_get_expanded (GIMP_VIEWABLE (current)) &&
|
|
gimp_container_get_n_children (current_container) > 0)
|
|
{
|
|
select_index = 0;
|
|
container = current_container;
|
|
}
|
|
else
|
|
{
|
|
select_index = gimp_container_get_child_index (container, current) + 1;
|
|
if (select_index >= n_children)
|
|
{
|
|
while (TRUE)
|
|
{
|
|
GimpItem *parent;
|
|
GimpContainer *parent_container;
|
|
gint n_parent_children;
|
|
|
|
parent = gimp_item_get_parent (GIMP_ITEM (current));
|
|
if (parent == NULL)
|
|
break;
|
|
|
|
parent_container = gimp_item_get_container (parent);
|
|
n_parent_children = gimp_container_get_n_children (parent_container);
|
|
if (gimp_container_get_child_index (parent_container, GIMP_OBJECT (parent)) + 1 < n_parent_children)
|
|
{
|
|
container = parent_container;
|
|
select_index = gimp_container_get_child_index (parent_container, GIMP_OBJECT (parent)) + 1;
|
|
break;
|
|
}
|
|
|
|
current = GIMP_OBJECT (parent);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
if ((gint) select_type >= 0)
|
|
select_index = (gint) select_type;
|
|
else
|
|
g_return_val_if_reached (current);
|
|
break;
|
|
}
|
|
|
|
n_children = gimp_container_get_n_children (container);
|
|
select_index = CLAMP (select_index, 0, n_children - 1);
|
|
|
|
return gimp_container_get_child_by_index (container, select_index);
|
|
}
|
|
|
|
void
|
|
action_message (GimpDisplay *display,
|
|
GObject *object,
|
|
const gchar *format,
|
|
...)
|
|
{
|
|
GimpDisplayShell *shell = gimp_display_get_shell (display);
|
|
GimpStatusbar *statusbar = gimp_display_shell_get_statusbar (shell);
|
|
const gchar *icon_name = NULL;
|
|
va_list args;
|
|
|
|
if (GIMP_IS_TOOL_OPTIONS (object))
|
|
{
|
|
GimpToolInfo *tool_info = GIMP_TOOL_OPTIONS (object)->tool_info;
|
|
|
|
icon_name = gimp_viewable_get_icon_name (GIMP_VIEWABLE (tool_info));
|
|
}
|
|
else if (GIMP_IS_VIEWABLE (object))
|
|
{
|
|
icon_name = gimp_viewable_get_icon_name (GIMP_VIEWABLE (object));
|
|
}
|
|
|
|
va_start (args, format);
|
|
gimp_statusbar_push_temp_valist (statusbar, GIMP_MESSAGE_INFO,
|
|
icon_name, format, args);
|
|
va_end (args);
|
|
}
|