mirror of https://github.com/GNOME/gimp.git
app: new GimpSearchPopup widget.
Based on GimpPopup as parent, this is a generic search popup widget, which can display any list of action. The results construction logics is not part of the widget, and is built through a callback instead, which could allow to use it to create different dialogs.
This commit is contained in:
parent
b8902a7d95
commit
6a9d449eac
|
@ -302,6 +302,8 @@ libappwidgets_a_sources = \
|
|||
gimpsavedialog.h \
|
||||
gimpscalebutton.c \
|
||||
gimpscalebutton.h \
|
||||
gimpsearchpopup.c \
|
||||
gimpsearchpopup.h \
|
||||
gimpselectiondata.c \
|
||||
gimpselectiondata.h \
|
||||
gimpselectioneditor.c \
|
||||
|
|
|
@ -0,0 +1,766 @@
|
|||
/* GIMP - The GNU Image Manipulation Program
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* gimpsearchpopup.c
|
||||
* Copyright (C) 2015 Jehan <jehan at girinstud.io>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include <gdk/gdkkeysyms.h>
|
||||
|
||||
#include "libgimpbase/gimpbase.h"
|
||||
#include "libgimpwidgets/gimpwidgets.h"
|
||||
|
||||
#include "widgets-types.h"
|
||||
|
||||
#include "core/gimp.h"
|
||||
|
||||
#include "gimpaction.h"
|
||||
#include "gimppopup.h"
|
||||
#include "gimpsearchpopup.h"
|
||||
#include "gimpuimanager.h"
|
||||
|
||||
#include "gimp-intl.h"
|
||||
|
||||
enum
|
||||
{
|
||||
COLUMN_ICON,
|
||||
COLUMN_MARKUP,
|
||||
COLUMN_TOOLTIP,
|
||||
COLUMN_ACTION,
|
||||
COLUMN_SENSITIVE,
|
||||
COLUMN_SECTION,
|
||||
N_COL
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_GIMP,
|
||||
PROP_CALLBACK,
|
||||
PROP_CALLBACK_DATA
|
||||
};
|
||||
|
||||
struct _GimpSearchPopupPrivate
|
||||
{
|
||||
Gimp *gimp;
|
||||
GtkWidget *keyword_entry;
|
||||
GtkWidget *results_list;
|
||||
GtkWidget *list_view;
|
||||
|
||||
gint window_height;
|
||||
|
||||
GimpSearchPopupCallback build_results;
|
||||
gpointer build_results_data;
|
||||
};
|
||||
|
||||
/* GObject handlers */
|
||||
static void gimp_search_popup_constructed (GObject *object);
|
||||
static void gimp_search_popup_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void gimp_search_popup_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
|
||||
/* GimpPopup handlers */
|
||||
static void gimp_search_popup_confirm (GimpPopup *popup);
|
||||
|
||||
/* Signal handlers on the search entry */
|
||||
static gboolean keyword_entry_on_key_press_event (GtkWidget *widget,
|
||||
GdkEventKey *event,
|
||||
GimpSearchPopup *popup);
|
||||
static gboolean keyword_entry_on_key_release_event (GtkWidget *widget,
|
||||
GdkEventKey *event,
|
||||
GimpSearchPopup *popup);
|
||||
/* Signal handlers on the results list */
|
||||
static gboolean results_list_on_key_press_event (GtkWidget *widget,
|
||||
GdkEventKey *kevent,
|
||||
GimpSearchPopup *popup);
|
||||
static void results_list_on_row_activated (GtkTreeView *treeview,
|
||||
GtkTreePath *path,
|
||||
GtkTreeViewColumn *col,
|
||||
GimpSearchPopup *popup);
|
||||
/* Signal handlers on the popup */
|
||||
static gboolean gimp_search_popup_on_configured (GtkWindow *window,
|
||||
GdkEvent *event,
|
||||
GimpSearchPopup *popup);
|
||||
/* Utils */
|
||||
static void gimp_search_popup_run_selected (GimpSearchPopup *popup);
|
||||
static void gimp_search_popup_setup_results (GtkWidget **results_list,
|
||||
GtkWidget **list_view);
|
||||
|
||||
static gchar * gimp_search_popup_find_accel_label (GtkAction *action);
|
||||
static gboolean gimp_search_popup_view_accel_find_func (GtkAccelKey *key,
|
||||
GClosure *closure,
|
||||
gpointer data);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (GimpSearchPopup, gimp_search_popup, GIMP_TYPE_POPUP)
|
||||
|
||||
#define parent_class gimp_search_popup_parent_class
|
||||
|
||||
static void
|
||||
gimp_search_popup_class_init (GimpSearchPopupClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GimpPopupClass *popup_class = GIMP_POPUP_CLASS (klass);
|
||||
GtkBindingSet *binding_set;
|
||||
|
||||
object_class->constructed = gimp_search_popup_constructed;
|
||||
object_class->set_property = gimp_search_popup_set_property;
|
||||
object_class->get_property = gimp_search_popup_get_property;
|
||||
|
||||
popup_class->confirm = gimp_search_popup_confirm;
|
||||
|
||||
/**
|
||||
* GimpSearchPopup:gimp:
|
||||
*
|
||||
* The #Gimp object.
|
||||
*/
|
||||
g_object_class_install_property (object_class, PROP_GIMP,
|
||||
g_param_spec_object ("gimp",
|
||||
NULL, NULL,
|
||||
G_TYPE_OBJECT,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY));
|
||||
/**
|
||||
* GimpSearchPopup:callback:
|
||||
*
|
||||
* The #GimpSearchPopupCallback used to fill in results.
|
||||
*/
|
||||
g_object_class_install_property (object_class, PROP_CALLBACK,
|
||||
g_param_spec_pointer ("callback", NULL, NULL,
|
||||
GIMP_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY));
|
||||
/**
|
||||
* GimpSearchPopup:callback-data:
|
||||
*
|
||||
* The #GPointer fed as last parameter to the #GimpSearchPopupCallback.
|
||||
*/
|
||||
g_object_class_install_property (object_class, PROP_CALLBACK_DATA,
|
||||
g_param_spec_pointer ("callback-data", NULL, NULL,
|
||||
GIMP_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY));
|
||||
|
||||
/* We don't want space to activate actions in the search widget, since
|
||||
* we allow search with spaces in it. */
|
||||
binding_set = gtk_binding_set_by_class (g_type_class_peek (GIMP_TYPE_POPUP));
|
||||
|
||||
gtk_binding_entry_remove (binding_set, GDK_KEY_space, 0);
|
||||
gtk_binding_entry_remove (binding_set, GDK_KEY_KP_Space, 0);
|
||||
|
||||
g_type_class_add_private (klass, sizeof (GimpSearchPopupPrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_search_popup_init (GimpSearchPopup *search_popup)
|
||||
{
|
||||
search_popup->priv = G_TYPE_INSTANCE_GET_PRIVATE (search_popup,
|
||||
GIMP_TYPE_SEARCH_POPUP,
|
||||
GimpSearchPopupPrivate);
|
||||
}
|
||||
|
||||
/************ Public Functions ****************/
|
||||
|
||||
/**
|
||||
* gimp_search_popup_new:
|
||||
* @gimp: #Gimp object.
|
||||
* @role: the role to give to the #GtkWindow.
|
||||
* @title: the #GtkWindow title.
|
||||
* @callback: the #GimpSearchPopupCallback used to fill in results.
|
||||
* @callback_data: data fed to @callback.
|
||||
*
|
||||
* Returns: a new #GimpSearchPopup.
|
||||
*/
|
||||
GtkWidget *
|
||||
gimp_search_popup_new (Gimp *gimp,
|
||||
const gchar *role,
|
||||
const gchar *title,
|
||||
GimpSearchPopupCallback callback,
|
||||
gpointer callback_data)
|
||||
{
|
||||
GtkWidget *widget;
|
||||
|
||||
widget = g_object_new (GIMP_TYPE_SEARCH_POPUP,
|
||||
"type", GTK_WINDOW_TOPLEVEL,
|
||||
"decorated", TRUE,
|
||||
"modal", TRUE,
|
||||
"role", role,
|
||||
"title", title,
|
||||
|
||||
"gimp", gimp,
|
||||
"callback", callback,
|
||||
"callback-data", callback_data,
|
||||
NULL);
|
||||
|
||||
|
||||
return widget;
|
||||
}
|
||||
|
||||
/**
|
||||
* gimp_search_popup_add_result:
|
||||
* @popup: the #GimpSearchPopup.
|
||||
* @action: a #GtkAction to add in results list.
|
||||
* @section: the section to add @action.
|
||||
*
|
||||
* Adds @action in the @popup's results at @section.
|
||||
* The section only indicates relative order. If you want some items
|
||||
* to appear before other, simply use lower @section.
|
||||
*/
|
||||
void
|
||||
gimp_search_popup_add_result (GimpSearchPopup *popup,
|
||||
GtkAction *action,
|
||||
gint section)
|
||||
{
|
||||
GtkTreeIter iter;
|
||||
GtkTreeIter next_section;
|
||||
GtkListStore *store;
|
||||
GtkTreeModel *model;
|
||||
gchar *markup;
|
||||
gchar *action_name;
|
||||
gchar *label;
|
||||
gchar *escaped_label = NULL;
|
||||
const gchar *icon_name;
|
||||
gchar *accel_string;
|
||||
gchar *escaped_accel = NULL;
|
||||
gboolean has_shortcut = FALSE;
|
||||
const gchar *tooltip;
|
||||
gchar *escaped_tooltip = NULL;
|
||||
gboolean has_tooltip = FALSE;
|
||||
|
||||
label = g_strstrip (gimp_strip_uline (gtk_action_get_label (action)));
|
||||
|
||||
if (! label || strlen (label) == 0)
|
||||
{
|
||||
g_free (label);
|
||||
return;
|
||||
}
|
||||
|
||||
escaped_label = g_markup_escape_text (label, -1);
|
||||
|
||||
if (GTK_IS_TOGGLE_ACTION (action))
|
||||
{
|
||||
if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
|
||||
icon_name = "gtk-ok";
|
||||
else
|
||||
icon_name = "gtk-no";
|
||||
}
|
||||
else
|
||||
{
|
||||
icon_name = gtk_action_get_icon_name (action);
|
||||
}
|
||||
|
||||
accel_string = gimp_search_popup_find_accel_label (action);
|
||||
if (accel_string != NULL)
|
||||
{
|
||||
escaped_accel = g_markup_escape_text (accel_string, -1);
|
||||
has_shortcut = TRUE;
|
||||
}
|
||||
|
||||
tooltip = gtk_action_get_tooltip (action);
|
||||
if (tooltip != NULL)
|
||||
{
|
||||
escaped_tooltip = g_markup_escape_text (tooltip, -1);
|
||||
has_tooltip = TRUE;
|
||||
}
|
||||
|
||||
markup = g_strdup_printf ("%s<small>%s%s%s<span weight='light'>%s</span></small>",
|
||||
escaped_label,
|
||||
has_shortcut ? " | " : "",
|
||||
has_shortcut ? escaped_accel : "",
|
||||
has_tooltip ? "\n" : "",
|
||||
has_tooltip ? escaped_tooltip : "");
|
||||
|
||||
action_name = g_markup_escape_text (gtk_action_get_name (action), -1);
|
||||
|
||||
model = gtk_tree_view_get_model (GTK_TREE_VIEW (popup->priv->results_list));
|
||||
store = GTK_LIST_STORE (model);
|
||||
if (gtk_tree_model_get_iter_first (model, &next_section))
|
||||
{
|
||||
while (TRUE)
|
||||
{
|
||||
gint iter_section;
|
||||
|
||||
gtk_tree_model_get (model, &next_section,
|
||||
COLUMN_SECTION, &iter_section, -1);
|
||||
if (iter_section > section)
|
||||
{
|
||||
gtk_list_store_insert_before (store, &iter, &next_section);
|
||||
break;
|
||||
}
|
||||
else if (! gtk_tree_model_iter_next (model, &next_section))
|
||||
{
|
||||
gtk_list_store_append (store, &iter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_list_store_append (store, &iter);
|
||||
}
|
||||
|
||||
gtk_list_store_set (store, &iter,
|
||||
COLUMN_ICON, icon_name,
|
||||
COLUMN_MARKUP, markup,
|
||||
COLUMN_TOOLTIP, action_name,
|
||||
COLUMN_ACTION, action,
|
||||
COLUMN_SECTION, section,
|
||||
COLUMN_SENSITIVE, gtk_action_is_sensitive (action),
|
||||
-1);
|
||||
|
||||
g_free (accel_string);
|
||||
g_free (markup);
|
||||
g_free (action_name);
|
||||
g_free (label);
|
||||
g_free (escaped_accel);
|
||||
g_free (escaped_label);
|
||||
g_free (escaped_tooltip);
|
||||
}
|
||||
|
||||
/************ Private Functions ****************/
|
||||
|
||||
static void
|
||||
gimp_search_popup_constructed (GObject *object)
|
||||
{
|
||||
GimpSearchPopup *popup = GIMP_SEARCH_POPUP (object);
|
||||
GdkScreen *screen = gdk_screen_get_default ();
|
||||
GtkWidget *main_vbox;
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->constructed (object);
|
||||
|
||||
main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
|
||||
gtk_container_add (GTK_CONTAINER (popup), main_vbox);
|
||||
gtk_widget_show (main_vbox);
|
||||
|
||||
popup->priv->keyword_entry = gtk_entry_new ();
|
||||
gtk_entry_set_icon_from_icon_name (GTK_ENTRY (popup->priv->keyword_entry),
|
||||
GTK_ENTRY_ICON_PRIMARY, "edit-find");
|
||||
gtk_box_pack_start (GTK_BOX (main_vbox),
|
||||
popup->priv->keyword_entry,
|
||||
FALSE, FALSE, 0);
|
||||
gtk_widget_show (popup->priv->keyword_entry);
|
||||
|
||||
gimp_search_popup_setup_results (&popup->priv->results_list,
|
||||
&popup->priv->list_view);
|
||||
gtk_box_pack_start (GTK_BOX (main_vbox),
|
||||
popup->priv->list_view, TRUE, TRUE, 0);
|
||||
|
||||
gtk_widget_set_events (GTK_WIDGET (object),
|
||||
GDK_KEY_RELEASE_MASK |
|
||||
GDK_KEY_PRESS_MASK |
|
||||
GDK_BUTTON_PRESS_MASK |
|
||||
GDK_SCROLL_MASK);
|
||||
|
||||
g_signal_connect (popup->priv->keyword_entry, "key-press-event",
|
||||
G_CALLBACK (keyword_entry_on_key_press_event),
|
||||
popup);
|
||||
g_signal_connect (popup->priv->keyword_entry, "key-release-event",
|
||||
G_CALLBACK (keyword_entry_on_key_release_event),
|
||||
popup);
|
||||
|
||||
g_signal_connect (popup->priv->results_list, "key-press-event",
|
||||
G_CALLBACK (results_list_on_key_press_event),
|
||||
popup);
|
||||
g_signal_connect (popup->priv->results_list, "row-activated",
|
||||
G_CALLBACK (results_list_on_row_activated),
|
||||
popup);
|
||||
|
||||
g_signal_connect (popup, "configure-event",
|
||||
G_CALLBACK (gimp_search_popup_on_configured),
|
||||
popup);
|
||||
|
||||
popup->priv->window_height = gdk_screen_get_height (screen) / 2;
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_search_popup_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GimpSearchPopup *search_popup = GIMP_SEARCH_POPUP (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_GIMP:
|
||||
search_popup->priv->gimp = g_value_get_object (value);
|
||||
break;
|
||||
case PROP_CALLBACK:
|
||||
search_popup->priv->build_results = g_value_get_pointer (value);
|
||||
break;
|
||||
case PROP_CALLBACK_DATA:
|
||||
search_popup->priv->build_results_data = g_value_get_pointer (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_search_popup_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GimpSearchPopup *search_popup = GIMP_SEARCH_POPUP (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_GIMP:
|
||||
g_value_set_object (value, search_popup->priv->gimp);
|
||||
break;
|
||||
case PROP_CALLBACK:
|
||||
g_value_set_pointer (value, search_popup->priv->build_results);
|
||||
break;
|
||||
case PROP_CALLBACK_DATA:
|
||||
g_value_set_pointer (value, search_popup->priv->build_results_data);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_search_popup_confirm (GimpPopup *popup)
|
||||
{
|
||||
GimpSearchPopup *search_popup = GIMP_SEARCH_POPUP (popup);
|
||||
|
||||
gimp_search_popup_run_selected (search_popup);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
keyword_entry_on_key_press_event (GtkWidget *widget,
|
||||
GdkEventKey *event,
|
||||
GimpSearchPopup *popup)
|
||||
{
|
||||
gboolean event_processed = FALSE;
|
||||
|
||||
if (event->keyval == GDK_KEY_Down &&
|
||||
gtk_widget_get_visible (popup->priv->list_view))
|
||||
{
|
||||
GtkTreeView *tree_view = GTK_TREE_VIEW (popup->priv->results_list);
|
||||
|
||||
/* When hitting the down key while editing, select directly the
|
||||
* second item, since the first could have run directly with
|
||||
* Enter. */
|
||||
gtk_tree_selection_select_path (gtk_tree_view_get_selection (tree_view),
|
||||
gtk_tree_path_new_from_string ("1"));
|
||||
gtk_widget_grab_focus (GTK_WIDGET (popup->priv->results_list));
|
||||
event_processed = TRUE;
|
||||
}
|
||||
|
||||
return event_processed;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
keyword_entry_on_key_release_event (GtkWidget *widget,
|
||||
GdkEventKey *event,
|
||||
GimpSearchPopup *popup)
|
||||
{
|
||||
GtkTreeView *tree_view = GTK_TREE_VIEW (popup->priv->results_list);
|
||||
gchar *entry_text;
|
||||
gint width;
|
||||
|
||||
/* These keys are already managed by key bindings. */
|
||||
if (event->keyval == GDK_KEY_Escape ||
|
||||
event->keyval == GDK_KEY_Return ||
|
||||
event->keyval == GDK_KEY_KP_Enter ||
|
||||
event->keyval == GDK_KEY_ISO_Enter)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gtk_window_get_size (GTK_WINDOW (popup), &width, NULL);
|
||||
entry_text = g_strstrip (gtk_editable_get_chars (GTK_EDITABLE (widget), 0, -1));
|
||||
|
||||
if (strcmp (entry_text, "") != 0)
|
||||
{
|
||||
gtk_window_resize (GTK_WINDOW (popup),
|
||||
width, popup->priv->window_height);
|
||||
gtk_list_store_clear (GTK_LIST_STORE (gtk_tree_view_get_model (tree_view)));
|
||||
gtk_widget_show_all (popup->priv->list_view);
|
||||
popup->priv->build_results (popup, entry_text,
|
||||
popup->priv->build_results_data);
|
||||
gtk_tree_selection_select_path (gtk_tree_view_get_selection (tree_view),
|
||||
gtk_tree_path_new_from_string ("0"));
|
||||
}
|
||||
else if (strcmp (entry_text, "") == 0 && (event->keyval == GDK_KEY_Down))
|
||||
{
|
||||
gtk_window_resize (GTK_WINDOW (popup),
|
||||
width, popup->priv->window_height);
|
||||
gtk_list_store_clear (GTK_LIST_STORE (gtk_tree_view_get_model (tree_view)));
|
||||
gtk_widget_show_all (popup->priv->list_view);
|
||||
popup->priv->build_results (popup, NULL,
|
||||
popup->priv->build_results_data);
|
||||
gtk_tree_selection_select_path (gtk_tree_view_get_selection (tree_view),
|
||||
gtk_tree_path_new_from_string ("0"));
|
||||
}
|
||||
else
|
||||
{
|
||||
GtkTreeSelection *selection;
|
||||
GtkTreeModel *model;
|
||||
GtkTreeIter iter;
|
||||
|
||||
selection = gtk_tree_view_get_selection (tree_view);
|
||||
gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
|
||||
|
||||
if (gtk_tree_selection_get_selected (selection, &model, &iter))
|
||||
{
|
||||
GtkTreePath *path;
|
||||
|
||||
path = gtk_tree_model_get_path (model, &iter);
|
||||
gtk_tree_selection_unselect_path (selection, path);
|
||||
|
||||
gtk_tree_path_free (path);
|
||||
}
|
||||
|
||||
gtk_widget_hide (popup->priv->list_view);
|
||||
gtk_window_resize (GTK_WINDOW (popup), width, 1);
|
||||
}
|
||||
|
||||
g_free (entry_text);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
results_list_on_key_press_event (GtkWidget *widget,
|
||||
GdkEventKey *kevent,
|
||||
GimpSearchPopup *popup)
|
||||
{
|
||||
/* These keys are already managed by key bindings. */
|
||||
g_return_if_fail (kevent->keyval != GDK_KEY_Escape &&
|
||||
kevent->keyval != GDK_KEY_Return &&
|
||||
kevent->keyval != GDK_KEY_KP_Enter &&
|
||||
kevent->keyval != GDK_KEY_ISO_Enter);
|
||||
|
||||
switch (kevent->keyval)
|
||||
{
|
||||
case GDK_KEY_Up:
|
||||
{
|
||||
gboolean event_processed = FALSE;
|
||||
GtkTreeSelection *selection;
|
||||
GtkTreeModel *model;
|
||||
GtkTreeIter iter;
|
||||
|
||||
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (popup->priv->results_list));
|
||||
gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
|
||||
|
||||
if (gtk_tree_selection_get_selected (selection, &model, &iter))
|
||||
{
|
||||
GtkTreePath *path = gtk_tree_model_get_path (model, &iter);
|
||||
|
||||
if (strcmp (gtk_tree_path_to_string (path), "0") == 0)
|
||||
{
|
||||
gint start_pos;
|
||||
gint end_pos;
|
||||
|
||||
gtk_editable_get_selection_bounds (GTK_EDITABLE (popup->priv->keyword_entry),
|
||||
&start_pos, &end_pos);
|
||||
gtk_widget_grab_focus ((GTK_WIDGET (popup->priv->keyword_entry)));
|
||||
gtk_editable_select_region (GTK_EDITABLE (popup->priv->keyword_entry),
|
||||
start_pos, end_pos);
|
||||
|
||||
event_processed = TRUE;
|
||||
}
|
||||
|
||||
gtk_tree_path_free (path);
|
||||
}
|
||||
|
||||
return event_processed;
|
||||
}
|
||||
case GDK_KEY_Down:
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
default:
|
||||
{
|
||||
gint start_pos;
|
||||
gint end_pos;
|
||||
|
||||
gtk_editable_get_selection_bounds (GTK_EDITABLE (popup->priv->keyword_entry),
|
||||
&start_pos, &end_pos);
|
||||
gtk_widget_grab_focus ((GTK_WIDGET (popup->priv->keyword_entry)));
|
||||
gtk_editable_select_region (GTK_EDITABLE (popup->priv->keyword_entry),
|
||||
start_pos, end_pos);
|
||||
gtk_widget_event (GTK_WIDGET (popup->priv->keyword_entry),
|
||||
(GdkEvent *) kevent);
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
results_list_on_row_activated (GtkTreeView *treeview,
|
||||
GtkTreePath *path,
|
||||
GtkTreeViewColumn *col,
|
||||
GimpSearchPopup *popup)
|
||||
{
|
||||
gimp_search_popup_run_selected (popup);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gimp_search_popup_on_configured (GtkWindow *window,
|
||||
GdkEvent *event,
|
||||
GimpSearchPopup *popup)
|
||||
{
|
||||
if (gtk_widget_get_visible (GTK_WIDGET (window)) &&
|
||||
gtk_widget_get_visible (popup->priv->list_view))
|
||||
{
|
||||
gtk_window_get_size (GTK_WINDOW (popup),
|
||||
NULL, &popup->priv->window_height);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_search_popup_run_selected (GimpSearchPopup *popup)
|
||||
{
|
||||
GtkTreeSelection *selection;
|
||||
GtkTreeModel *model;
|
||||
GtkTreeIter iter;
|
||||
|
||||
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (popup->priv->results_list));
|
||||
gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
|
||||
|
||||
if (gtk_tree_selection_get_selected (selection, &model, &iter))
|
||||
{
|
||||
GtkAction *action;
|
||||
|
||||
gtk_tree_model_get (model, &iter, COLUMN_ACTION, &action, -1);
|
||||
|
||||
if (gtk_action_is_sensitive (action))
|
||||
{
|
||||
gtk_action_activate (action);
|
||||
/* Close the search popup on activation. */
|
||||
GIMP_POPUP_CLASS (parent_class)->cancel (GIMP_POPUP (popup));
|
||||
}
|
||||
|
||||
g_object_unref (action);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_search_popup_setup_results (GtkWidget **results_list,
|
||||
GtkWidget **list_view)
|
||||
{
|
||||
gint wid1 = 100;
|
||||
GtkListStore *store;
|
||||
GtkCellRenderer *cell;
|
||||
GtkTreeViewColumn *column;
|
||||
|
||||
*list_view = GTK_WIDGET (gtk_scrolled_window_new (NULL, NULL));
|
||||
store = gtk_list_store_new (N_COL,
|
||||
G_TYPE_STRING,
|
||||
G_TYPE_STRING,
|
||||
G_TYPE_STRING,
|
||||
GTK_TYPE_ACTION,
|
||||
G_TYPE_BOOLEAN,
|
||||
G_TYPE_INT);
|
||||
*results_list = GTK_WIDGET (gtk_tree_view_new_with_model (GTK_TREE_MODEL (store)));
|
||||
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (*results_list), FALSE);
|
||||
#ifdef GIMP_UNSTABLE
|
||||
gtk_tree_view_set_tooltip_column (GTK_TREE_VIEW (*results_list),
|
||||
COLUMN_TOOLTIP);
|
||||
#endif
|
||||
|
||||
cell = gtk_cell_renderer_pixbuf_new ();
|
||||
column = gtk_tree_view_column_new_with_attributes (NULL, cell,
|
||||
"icon-name", COLUMN_ICON,
|
||||
"sensitive", COLUMN_SENSITIVE,
|
||||
NULL);
|
||||
gtk_tree_view_append_column (GTK_TREE_VIEW (*results_list), column);
|
||||
gtk_tree_view_column_set_min_width (column, 22);
|
||||
|
||||
cell = gtk_cell_renderer_text_new ();
|
||||
column = gtk_tree_view_column_new_with_attributes (NULL, cell,
|
||||
"markup", COLUMN_MARKUP,
|
||||
"sensitive", COLUMN_SENSITIVE,
|
||||
NULL);
|
||||
gtk_tree_view_append_column (GTK_TREE_VIEW (*results_list), column);
|
||||
gtk_tree_view_column_set_max_width (column, wid1);
|
||||
|
||||
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (*list_view),
|
||||
GTK_POLICY_NEVER,
|
||||
GTK_POLICY_AUTOMATIC);
|
||||
|
||||
gtk_container_add (GTK_CONTAINER (*list_view), *results_list);
|
||||
g_object_unref (G_OBJECT (store));
|
||||
}
|
||||
|
||||
static gchar *
|
||||
gimp_search_popup_find_accel_label (GtkAction *action)
|
||||
{
|
||||
guint accel_key = 0;
|
||||
GdkModifierType accel_mask = 0;
|
||||
GClosure *accel_closure = NULL;
|
||||
gchar *accel_string;
|
||||
GtkAccelGroup *accel_group;
|
||||
GimpUIManager *manager;
|
||||
|
||||
manager = gimp_ui_managers_from_name ("<Image>")->data;
|
||||
accel_group = gtk_ui_manager_get_accel_group (GTK_UI_MANAGER (manager));
|
||||
accel_closure = gtk_action_get_accel_closure (action);
|
||||
|
||||
if (accel_closure)
|
||||
{
|
||||
GtkAccelKey *key;
|
||||
|
||||
key = gtk_accel_group_find (accel_group,
|
||||
gimp_search_popup_view_accel_find_func,
|
||||
accel_closure);
|
||||
if (key &&
|
||||
key->accel_key &&
|
||||
key->accel_flags & GTK_ACCEL_VISIBLE)
|
||||
{
|
||||
accel_key = key->accel_key;
|
||||
accel_mask = key->accel_mods;
|
||||
}
|
||||
}
|
||||
|
||||
accel_string = gtk_accelerator_get_label (accel_key, accel_mask);
|
||||
|
||||
if (strcmp (g_strstrip (accel_string), "") == 0)
|
||||
{
|
||||
/* The value returned by gtk_accelerator_get_label() must be freed after use. */
|
||||
g_free (accel_string);
|
||||
accel_string = NULL;
|
||||
}
|
||||
|
||||
return accel_string;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gimp_search_popup_view_accel_find_func (GtkAccelKey *key,
|
||||
GClosure *closure,
|
||||
gpointer data)
|
||||
{
|
||||
return (GClosure *) data == closure;
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
/* GIMP - The GNU Image Manipulation Program
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* gimpsearchpopup.h
|
||||
* Copyright (C) 2015 Jehan <jehan at girinstud.io>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __GIMP_SEARCH_POPUP_H__
|
||||
#define __GIMP_SEARCH_POPUP_H__
|
||||
|
||||
#include "gimppopup.h"
|
||||
|
||||
#define GIMP_TYPE_SEARCH_POPUP (gimp_search_popup_get_type ())
|
||||
#define GIMP_SEARCH_POPUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_SEARCH_POPUP, GimpSearchPopup))
|
||||
#define GIMP_SEARCH_POPUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_SEARCH_POPUP, GimpSearchPopupClass))
|
||||
#define GIMP_IS_SEARCH_POPUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_SEARCH_POPUP))
|
||||
#define GIMP_IS_SEARCH_POPUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_SEARCH_POPUP))
|
||||
#define GIMP_SEARCH_POPUP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_SEARCH_POPUP, GimpSearchPopupClass))
|
||||
|
||||
/**
|
||||
* GimpSearchPopupCallback:
|
||||
* @popup: the #GimpSearchPopup to operate on.
|
||||
* @search: the text searched.
|
||||
*
|
||||
* Callback used by @popup to fill in its result list.
|
||||
* It should make use of gimp_search_popup_add_result() to fill in
|
||||
* results.
|
||||
*/
|
||||
typedef struct _GimpSearchPopup GimpSearchPopup;
|
||||
typedef struct _GimpSearchPopupClass GimpSearchPopupClass;
|
||||
typedef struct _GimpSearchPopupPrivate GimpSearchPopupPrivate;
|
||||
|
||||
typedef void (*GimpSearchPopupCallback) (GimpSearchPopup *popup,
|
||||
const gchar *search,
|
||||
gpointer data);
|
||||
|
||||
struct _GimpSearchPopup
|
||||
{
|
||||
GimpPopup parent_instance;
|
||||
|
||||
GimpSearchPopupPrivate *priv;
|
||||
};
|
||||
|
||||
struct _GimpSearchPopupClass
|
||||
{
|
||||
GimpPopupClass parent_class;
|
||||
};
|
||||
|
||||
GType gimp_search_popup_get_type (void);
|
||||
|
||||
GtkWidget * gimp_search_popup_new (Gimp *gimp,
|
||||
const gchar *role,
|
||||
const gchar *title,
|
||||
GimpSearchPopupCallback callback,
|
||||
gpointer callback_data);
|
||||
|
||||
void gimp_search_popup_add_result (GimpSearchPopup *popup,
|
||||
GtkAction *action,
|
||||
gint section);
|
||||
|
||||
#endif /* __GIMP_SEARCH_POPUP_H__ */
|
Loading…
Reference in New Issue