[gedit/animation: 1/3] Add animation framework
- From: Ignacio Casal Quinteiro <icq src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gedit/animation: 1/3] Add animation framework
- Date: Tue, 7 Sep 2010 13:17:03 +0000 (UTC)
commit fc2b549c5a0f0cce34e831384f7bcce18b9a7f14
Author: Ignacio Casal Quinteiro <icq gnome org>
Date: Thu Jul 15 11:54:03 2010 +0200
Add animation framework
Now the interactive search uses the animation framework to provide
a chrome like search dialog.
configure.ac | 1 +
gedit/Makefile.am | 21 +-
gedit/gedit-commands-search.c | 8 +-
gedit/gedit-overlay.c | 612 +++++++++
gedit/gedit-overlay.h | 80 ++
gedit/gedit-rounded-frame.c | 231 ++++
gedit/gedit-rounded-frame.h | 61 +
gedit/gedit-tab.c | 6 +
gedit/gedit-tab.h | 1 +
gedit/gedit-view-frame.c | 1249 +++++++++++++++++++-
gedit/gedit-view.c | 1307 +-------------------
gedit/theatrics/Makefile.am | 52 +
gedit/theatrics/gedit-theatrics-actor.c | 279 +++++
gedit/theatrics/gedit-theatrics-actor.h | 90 ++
gedit/theatrics/gedit-theatrics-animated-widget.c | 643 ++++++++++
gedit/theatrics/gedit-theatrics-animated-widget.h | 108 ++
gedit/theatrics/gedit-theatrics-choreographer.c | 85 ++
gedit/theatrics/gedit-theatrics-choreographer.h | 74 ++
.../gedit-theatrics-enum-types.c.template | 39 +
.../gedit-theatrics-enum-types.h.template | 27 +
gedit/theatrics/gedit-theatrics-marshal.list | 1 +
gedit/theatrics/gedit-theatrics-stage.c | 313 +++++
gedit/theatrics/gedit-theatrics-stage.h | 87 ++
gedit/theatrics/gedit-theatrics-utils.c | 131 ++
gedit/theatrics/gedit-theatrics-utils.h | 48 +
tests/Makefile.am | 8 +
tests/test-overlay.c | 62 +
tests/test-rounded-frame.c | 29 +
28 files changed, 4370 insertions(+), 1283 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index fd0deec..478c36e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -402,6 +402,7 @@ docs/Makefile
docs/reference/Makefile
gedit/dialogs/Makefile
gedit/smclient/Makefile
+gedit/theatrics/Makefile
gedit/Makefile
help/Makefile
pixmaps/Makefile
diff --git a/gedit/Makefile.am b/gedit/Makefile.am
index 3240cb1..4aca99b 100644
--- a/gedit/Makefile.am
+++ b/gedit/Makefile.am
@@ -1,5 +1,5 @@
## Process this file with automake to produce Makefile.in
-SUBDIRS = dialogs smclient
+SUBDIRS = dialogs smclient theatrics
bin_PROGRAMS = gedit
@@ -40,7 +40,8 @@ libgedit_la_LDFLAGS = -export-dynamic -no-undefined -export-symbols-regex "^[[^_
libgedit_la_LIBADD = \
dialogs/libdialogs.la \
- smclient/libeggsmclient.la
+ smclient/libeggsmclient.la \
+ theatrics/libtheatrics.la
# GEDIT_LIBS must be the last to ensure correct order on some platforms
libgedit_la_LIBADD += $(GEDIT_LIBS)
@@ -114,9 +115,11 @@ NOINST_H_FILES = \
gedit-language-manager.h \
gedit-multi-notebook.h \
gedit-notebook.h \
+ gedit-overlay.h \
gedit-plugins-engine.h \
gedit-print-job.h \
gedit-print-preview.h \
+ gedit-rounded-frame.h \
gedit-session.h \
gedit-settings.h \
gedit-smart-charset-converter.h \
@@ -195,11 +198,13 @@ libgedit_c_files = \
gedit-message.c \
gedit-multi-notebook.c \
gedit-notebook.c \
+ gedit-overlay.c \
gedit-panel.c \
gedit-plugins-engine.c \
gedit-print-job.c \
gedit-print-preview.c \
gedit-progress-info-bar.c \
+ gedit-rounded-frame.c \
gedit-session.c \
gedit-settings.c \
gedit-smart-charset-converter.c \
@@ -260,6 +265,16 @@ EXTRA_DIST = \
CLEANFILES = $(BUILT_SOURCES)
+theatrics_files = \
+ ./theatrics/gedit-theatrics-actor.h \
+ ./theatrics/gedit-theatrics-actor.c \
+ ./theatrics/gedit-theatrics-animated-widget.h \
+ ./theatrics/gedit-theatrics-animated-widget.c \
+ ./theatrics/gedit-theatrics-choreographer.h \
+ ./theatrics/gedit-theatrics-choreographer.c \
+ ./theatrics/gedit-theatrics-stage.h \
+ ./theatrics/gedit-theatrics-stage.c
+
if HAVE_INTROSPECTION
-include $(INTROSPECTION_MAKEFILE)
INTROSPECTION_GIRS = Gedit-3.0.gir
@@ -269,7 +284,7 @@ INTROSPECTION_SCANNER_ARGS = -I$(top_srcdir) --warn-all
Gedit_3_0_gir_NAMESPACE = Gedit
Gedit_3_0_gir_VERSION = 3.0
Gedit_3_0_gir_PROGRAM = $(builddir)/gedit
-Gedit_3_0_gir_FILES = $(INST_H_FILES) $(libgedit_c_files)
+Gedit_3_0_gir_FILES = $(theatrics_files) $(INST_H_FILES) $(libgedit_c_files)
Gedit_3_0_gir_INCLUDES = Gtk-3.0 GtkSource-3.0
girdir = $(datadir)/gedit/gir-1.0
diff --git a/gedit/gedit-commands-search.c b/gedit/gedit-commands-search.c
index 02d1bad..f267189 100644
--- a/gedit/gedit-commands-search.c
+++ b/gedit/gedit-commands-search.c
@@ -41,6 +41,7 @@
#include "gedit-commands.h"
#include "gedit-debug.h"
#include "gedit-statusbar.h"
+#include "gedit-view-frame.h"
#include "gedit-window.h"
#include "gedit-window-private.h"
#include "gedit-utils.h"
@@ -692,9 +693,8 @@ _gedit_cmd_search_goto_line (GtkAction *action,
activating the binding for goto line has no effect */
gtk_widget_grab_focus (GTK_WIDGET (active_view));
-
/* goto line is builtin in GeditView, just activate
- * the corrisponding binding.
+ * the corresponding binding.
*/
gtk_bindings_activate (GTK_OBJECT (active_view),
GDK_i,
@@ -714,11 +714,11 @@ _gedit_cmd_search_incremental_search (GtkAction *action,
return;
/* Focus the view if needed: we need to focus the view otherwise
- activating the binding for incremental search has no effect */
+ activating the binding for goto line has no effect */
gtk_widget_grab_focus (GTK_WIDGET (active_view));
/* incremental search is builtin in GeditView, just activate
- * the corrisponding binding.
+ * the corresponding binding.
*/
gtk_bindings_activate (GTK_OBJECT (active_view),
GDK_k,
diff --git a/gedit/gedit-overlay.c b/gedit/gedit-overlay.c
new file mode 100644
index 0000000..c716f3f
--- /dev/null
+++ b/gedit/gedit-overlay.c
@@ -0,0 +1,612 @@
+/*
+ * gedit-overlay.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 2010 - Ignacio Casal Quinteiro
+ *
+ * Based on Mike Krüger <mkrueger novell com> work.
+ *
+ * gedit is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * gedit 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 gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#include "gedit-overlay.h"
+#include "gedit-marshal.h"
+#include "theatrics/gedit-theatrics-animation.h"
+#include "theatrics/gedit-theatrics-animated-widget.h"
+#include "theatrics/gedit-theatrics-stage.h"
+
+#define GEDIT_OVERLAY_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GEDIT_TYPE_OVERLAY, GeditOverlayPrivate))
+
+typedef struct _ContainerChild
+{
+ GtkWidget *child;
+ gint x;
+ gint y;
+
+ guint fixed_position : 1;
+ guint is_animated : 1;
+} ContainerChild;
+
+struct _GeditOverlayPrivate
+{
+ GtkWidget *main_widget;
+ GSList *children;
+
+ GtkAdjustment *hadjustment;
+ GtkAdjustment *vadjustment;
+ glong hadjustment_signal_id;
+ glong vadjustment_signal_id;
+
+ GeditTheatricsStage *stage;
+};
+
+enum
+{
+ PROP_0,
+ PROP_MAIN_WIDGET
+};
+
+enum
+{
+ SET_SCROLL_ADJUSTMENTS,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+G_DEFINE_TYPE (GeditOverlay, gedit_overlay, GTK_TYPE_CONTAINER)
+
+static void
+free_container_child (ContainerChild *child)
+{
+ g_slice_free (ContainerChild, child);
+}
+
+static void
+add_toplevel_widget (GeditOverlay *overlay,
+ GtkWidget *widget,
+ gboolean fixed_position,
+ gboolean is_animated,
+ gint x,
+ gint y)
+{
+ ContainerChild *child = g_slice_new (ContainerChild);
+
+ gtk_widget_set_parent (widget, GTK_WIDGET (overlay));
+ child->child = widget;
+ child->x = x;
+ child->y = y;
+ child->fixed_position = fixed_position;
+ child->is_animated = is_animated;
+
+ overlay->priv->children = g_slist_append (overlay->priv->children,
+ child);
+}
+
+static void
+gedit_overlay_finalize (GObject *object)
+{
+ GeditOverlay *overlay = GEDIT_OVERLAY (object);
+
+ g_slist_free (overlay->priv->children);
+
+ G_OBJECT_CLASS (gedit_overlay_parent_class)->finalize (object);
+}
+
+static void
+gedit_overlay_dispose (GObject *object)
+{
+ GeditOverlay *overlay = GEDIT_OVERLAY (object);
+
+ if (overlay->priv->stage != NULL)
+ {
+ g_object_unref (overlay->priv->stage);
+ overlay->priv->stage = NULL;
+ }
+
+ G_OBJECT_CLASS (gedit_overlay_parent_class)->dispose (object);
+}
+
+static void
+gedit_overlay_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GeditOverlay *overlay = GEDIT_OVERLAY (object);
+
+ switch (prop_id)
+ {
+ case PROP_MAIN_WIDGET:
+ g_value_set_object (value, overlay->priv->main_widget);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gedit_overlay_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GeditOverlay *overlay = GEDIT_OVERLAY (object);
+
+ switch (prop_id)
+ {
+ case PROP_MAIN_WIDGET:
+ {
+ overlay->priv->main_widget = g_value_get_object (value);
+ add_toplevel_widget (overlay,
+ overlay->priv->main_widget,
+ TRUE, FALSE, 0, 0);
+ break;
+ }
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gedit_overlay_destroy (GtkObject *object)
+{
+ GeditOverlay *overlay = GEDIT_OVERLAY (object);
+
+ if (overlay->priv->hadjustment != NULL)
+ {
+ g_signal_handler_disconnect (overlay->priv->hadjustment,
+ overlay->priv->hadjustment_signal_id);
+ overlay->priv->hadjustment = NULL;
+ }
+
+ if (overlay->priv->vadjustment != NULL)
+ {
+ g_signal_handler_disconnect (overlay->priv->vadjustment,
+ overlay->priv->vadjustment_signal_id);
+ overlay->priv->vadjustment = NULL;
+ }
+
+ GTK_OBJECT_CLASS (gedit_overlay_parent_class)->destroy (object);
+}
+
+static void
+gedit_overlay_realize (GtkWidget *widget)
+{
+ GdkWindowAttr attributes;
+ GtkAllocation allocation;
+ GdkWindowAttributesType mask;
+ GdkWindow *parent_window;
+ GdkWindow *window;
+ GtkStyle *style;
+
+ gtk_widget_set_realized (widget, TRUE);
+ gtk_widget_get_allocation (widget, &allocation);
+
+ parent_window = gtk_widget_get_parent_window (widget);
+ style = gtk_widget_get_style (widget);
+
+ attributes.window_type = GDK_WINDOW_CHILD;
+ attributes.x = allocation.x;
+ attributes.y = allocation.y;
+ attributes.width = allocation.width;
+ attributes.height = allocation.height;
+ attributes.wclass = GDK_INPUT_OUTPUT;
+ attributes.visual = gtk_widget_get_visual (widget);
+ attributes.colormap = gtk_widget_get_colormap (widget);
+ attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
+
+ mask = GDK_WA_X | GDK_WA_Y | GDK_WA_COLORMAP | GDK_WA_VISUAL;
+ window = gdk_window_new (parent_window, &attributes, mask);
+ gdk_window_set_user_data (window, widget);
+ gtk_widget_set_window (widget, window);
+
+ style = gtk_style_attach (style, window);
+ gtk_widget_set_style (widget, style);
+ gtk_style_set_background (style, window, GTK_STATE_NORMAL);
+}
+
+static void
+set_children_positions (GeditOverlay *overlay)
+{
+ GSList *l;
+
+ for (l = overlay->priv->children; l != NULL; l = g_slist_next (l))
+ {
+ ContainerChild *child = (ContainerChild *)l->data;
+ GtkRequisition req;
+ GtkAllocation alloc;
+
+ if (child->child == overlay->priv->main_widget)
+ continue;
+
+ gtk_widget_size_request (child->child, &req);
+
+ alloc.x = child->fixed_position ? child->x :
+ child->x * gtk_adjustment_get_value (overlay->priv->hadjustment);
+ alloc.y = child->fixed_position ? child->y :
+ child->y * gtk_adjustment_get_value (overlay->priv->vadjustment);
+ alloc.width = req.width;
+ alloc.height = req.height;
+
+ gtk_widget_size_allocate (child->child, &alloc);
+ }
+}
+
+static void
+gedit_overlay_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ GeditOverlay *overlay = GEDIT_OVERLAY (widget);
+ GtkAllocation alloc;
+
+ GTK_WIDGET_CLASS (gedit_overlay_parent_class)->size_allocate (widget, allocation);
+
+ alloc.x = 0;
+ alloc.y = 0;
+ alloc.width = allocation->width;
+ alloc.height = allocation->height;
+
+ gtk_widget_size_allocate (overlay->priv->main_widget,
+ &alloc);
+ set_children_positions (overlay);
+}
+
+static void
+gedit_overlay_add (GtkContainer *overlay,
+ GtkWidget *widget)
+{
+ add_toplevel_widget (GEDIT_OVERLAY (overlay), widget,
+ FALSE, FALSE, 0, 0);
+}
+
+static void
+gedit_overlay_remove (GtkContainer *overlay,
+ GtkWidget *widget)
+{
+ GeditOverlay *goverlay = GEDIT_OVERLAY (overlay);
+ GSList *l;
+
+ for (l = goverlay->priv->children; l != NULL; l = g_slist_next (l))
+ {
+ ContainerChild *child = (ContainerChild *)l->data;
+
+ if (child->child == widget)
+ {
+ gtk_widget_unparent (widget);
+ goverlay->priv->children = g_slist_remove (goverlay->priv->children,
+ child);
+ free_container_child (child);
+ }
+ }
+}
+
+static void
+gedit_overlay_forall (GtkContainer *overlay,
+ gboolean include_internals,
+ GtkCallback callback,
+ gpointer callback_data)
+{
+ GeditOverlay *goverlay = GEDIT_OVERLAY (overlay);
+ GSList *l;
+
+ for (l = goverlay->priv->children; l != NULL; l = g_slist_next (l))
+ {
+ ContainerChild *child = (ContainerChild *)l->data;
+
+ callback (child->child, callback_data);
+ }
+}
+
+static GType
+gedit_overlay_child_type (GtkContainer *overlay)
+{
+ return GTK_TYPE_WIDGET;
+}
+
+static void
+adjustment_value_changed (GtkAdjustment *adjustment,
+ GeditOverlay *overlay)
+{
+ set_children_positions (overlay);
+}
+
+static void
+gedit_overlay_set_scroll_adjustments (GeditOverlay *overlay,
+ GtkAdjustment *hadjustment,
+ GtkAdjustment *vadjustment)
+{
+ if (overlay->priv->hadjustment != NULL)
+ {
+ g_signal_handler_disconnect (overlay->priv->hadjustment,
+ overlay->priv->hadjustment_signal_id);
+ }
+
+ if (overlay->priv->vadjustment != NULL)
+ {
+ g_signal_handler_disconnect (overlay->priv->vadjustment,
+ overlay->priv->vadjustment_signal_id);
+ }
+
+ if (hadjustment != NULL)
+ {
+ overlay->priv->hadjustment_signal_id =
+ g_signal_connect (hadjustment,
+ "value-changed",
+ G_CALLBACK (adjustment_value_changed),
+ overlay);
+ }
+
+ if (vadjustment != NULL)
+ {
+ overlay->priv->vadjustment_signal_id =
+ g_signal_connect (vadjustment,
+ "value-changed",
+ G_CALLBACK (adjustment_value_changed),
+ overlay);
+ }
+
+ overlay->priv->hadjustment = hadjustment;
+ overlay->priv->vadjustment = vadjustment;
+
+ gtk_widget_set_scroll_adjustments (overlay->priv->main_widget,
+ hadjustment,
+ vadjustment);
+}
+
+static void
+gedit_overlay_class_init (GeditOverlayClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkObjectClass *gtkobject_class = GTK_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
+
+ object_class->finalize = gedit_overlay_finalize;
+ object_class->dispose = gedit_overlay_dispose;
+ object_class->get_property = gedit_overlay_get_property;
+ object_class->set_property = gedit_overlay_set_property;
+
+ gtkobject_class->destroy = gedit_overlay_destroy;
+
+ widget_class->realize = gedit_overlay_realize;
+ widget_class->size_allocate = gedit_overlay_size_allocate;
+
+ container_class->add = gedit_overlay_add;
+ container_class->remove = gedit_overlay_remove;
+ container_class->forall = gedit_overlay_forall;
+ container_class->child_type = gedit_overlay_child_type;
+
+ klass->set_scroll_adjustments = gedit_overlay_set_scroll_adjustments;
+
+ g_object_class_install_property (object_class, PROP_MAIN_WIDGET,
+ g_param_spec_object ("main-widget",
+ "Main Widget",
+ "The Main Widget",
+ GTK_TYPE_WIDGET,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ signals[SET_SCROLL_ADJUSTMENTS] =
+ g_signal_new ("set-scroll-adjustments",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (GeditOverlayClass, set_scroll_adjustments),
+ NULL, NULL,
+ gedit_marshal_VOID__OBJECT_OBJECT,
+ G_TYPE_NONE, 2,
+ GTK_TYPE_ADJUSTMENT,
+ GTK_TYPE_ADJUSTMENT);
+ widget_class->set_scroll_adjustments_signal = signals[SET_SCROLL_ADJUSTMENTS];
+
+ g_type_class_add_private (object_class, sizeof (GeditOverlayPrivate));
+}
+
+static void
+on_actor_step (GeditTheatricsStage *stage,
+ GeditTheatricsActor *actor,
+ GeditOverlay *overlay)
+{
+ GeditTheatricsAnimationState animation_state;
+ GeditTheatricsAnimatedWidget *anim_widget;
+
+ anim_widget = GEDIT_THEATRICS_ANIMATED_WIDGET (gedit_theatrics_actor_get_target (actor));
+ animation_state = gedit_theatrics_animated_widget_get_animation_state (anim_widget);
+
+ switch (animation_state)
+ {
+ case GEDIT_THEATRICS_ANIMATION_STATE_COMING:
+ {
+ gtk_widget_queue_draw (GTK_WIDGET (anim_widget));
+ gedit_theatrics_animated_widget_set_percent (anim_widget,
+ gedit_theatrics_actor_get_percent (actor));
+ if (gedit_theatrics_actor_get_expired (actor))
+ {
+ gedit_theatrics_animated_widget_set_animation_state (anim_widget,
+ GEDIT_THEATRICS_ANIMATION_STATE_IDLE);
+ }
+ break;
+ }
+ case GEDIT_THEATRICS_ANIMATION_STATE_INTENDING_TO_GO:
+ {
+ gedit_theatrics_animated_widget_set_animation_state (anim_widget,
+ GEDIT_THEATRICS_ANIMATION_STATE_GOING);
+ gedit_theatrics_animated_widget_set_bias (anim_widget,
+ gedit_theatrics_actor_get_percent (actor));
+ gedit_theatrics_actor_reset (actor, gedit_theatrics_animated_widget_get_duration (anim_widget) *
+ gedit_theatrics_actor_get_percent (actor));
+ break;
+ }
+ case GEDIT_THEATRICS_ANIMATION_STATE_GOING:
+ {
+ if (gedit_theatrics_actor_get_expired (actor))
+ {
+ gtk_container_remove (GTK_CONTAINER (overlay),
+ GTK_WIDGET (anim_widget));
+ return;
+ }
+ gedit_theatrics_animated_widget_set_percent (anim_widget, 1.0 - gedit_theatrics_actor_get_percent (actor));
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+static void
+remove_core (GeditOverlay *overlay,
+ GeditTheatricsAnimatedWidget *aw)
+{
+ GeditTheatricsAnimationState animation_state;
+
+ animation_state = gedit_theatrics_animated_widget_get_animation_state (aw);
+
+ if (animation_state == GEDIT_THEATRICS_ANIMATION_STATE_COMING)
+ {
+ gedit_theatrics_animated_widget_set_animation_state (aw, GEDIT_THEATRICS_ANIMATION_STATE_INTENDING_TO_GO);
+ }
+ else
+ {
+ GeditTheatricsChoreographerEasing easing;
+
+ easing = gedit_theatrics_animated_widget_get_easing (aw);
+
+ switch (easing)
+ {
+ case GEDIT_THEATRICS_CHOREOGRAPHER_EASING_QUADRATIC_IN:
+ gedit_theatrics_animated_widget_set_easing (
+ aw, GEDIT_THEATRICS_CHOREOGRAPHER_EASING_QUADRATIC_OUT);
+ break;
+ case GEDIT_THEATRICS_CHOREOGRAPHER_EASING_QUADRATIC_OUT:
+ gedit_theatrics_animated_widget_set_easing (
+ aw, GEDIT_THEATRICS_CHOREOGRAPHER_EASING_QUADRATIC_IN);
+ break;
+ case GEDIT_THEATRICS_CHOREOGRAPHER_EASING_EXPONENTIAL_IN:
+ gedit_theatrics_animated_widget_set_easing (
+ aw, GEDIT_THEATRICS_CHOREOGRAPHER_EASING_EXPONENTIAL_OUT);
+ break;
+ case GEDIT_THEATRICS_CHOREOGRAPHER_EASING_EXPONENTIAL_OUT:
+ gedit_theatrics_animated_widget_set_easing (
+ aw, GEDIT_THEATRICS_CHOREOGRAPHER_EASING_EXPONENTIAL_IN);
+ break;
+ default:
+ break;
+ }
+
+ gedit_theatrics_animated_widget_set_animation_state (aw, GEDIT_THEATRICS_ANIMATION_STATE_GOING);
+ gedit_theatrics_stage_add_with_duration (overlay->priv->stage,
+ G_OBJECT (aw),
+ gedit_theatrics_animated_widget_get_duration (aw));
+ }
+}
+
+static void
+on_remove_core (GeditTheatricsAnimatedWidget *aw,
+ GeditOverlay *overlay)
+{
+ remove_core (overlay, aw);
+}
+
+static void
+gedit_overlay_init (GeditOverlay *overlay)
+{
+ overlay->priv = GEDIT_OVERLAY_GET_PRIVATE (overlay);
+
+ overlay->priv->stage = gedit_theatrics_stage_new ();
+
+ g_signal_connect (overlay->priv->stage,
+ "actor-step",
+ G_CALLBACK (on_actor_step),
+ overlay);
+}
+
+GtkWidget *
+gedit_overlay_new (GtkWidget *main_widget)
+{
+ return GTK_WIDGET (g_object_new (GEDIT_TYPE_OVERLAY,
+ "main-widget", main_widget,
+ NULL));
+}
+
+void
+gedit_overlay_add_animated_widget (GeditOverlay *overlay,
+ GtkWidget *widget,
+ guint duration,
+ GeditTheatricsChoreographerEasing easing,
+ GeditTheatricsChoreographerBlocking blocking,
+ GtkOrientation orientation,
+ gint x,
+ gint y)
+{
+ GeditTheatricsAnimatedWidget *anim_widget;
+ GeditTheatricsActor *actor;
+ GtkAllocation widget_alloc;
+
+ anim_widget = gedit_theatrics_animated_widget_new (widget, duration,
+ easing,
+ blocking,
+ orientation);
+ gtk_widget_show (GTK_WIDGET (anim_widget));
+
+ g_signal_connect (anim_widget,
+ "remove-core",
+ G_CALLBACK (on_remove_core),
+ overlay);
+
+ gtk_widget_get_allocation (widget, &widget_alloc);
+ gedit_theatrics_animated_widget_set_end_padding (anim_widget,
+ widget_alloc.height);
+
+ actor = gedit_theatrics_stage_add_with_duration (overlay->priv->stage,
+ G_OBJECT (anim_widget),
+ duration);
+
+ add_toplevel_widget (overlay, GTK_WIDGET (anim_widget), TRUE,
+ TRUE, x, y);
+}
+
+void
+gedit_overlay_move_widget (GeditOverlay *overlay,
+ GtkWidget *widget,
+ gint x,
+ gint y)
+{
+ GSList *l;
+
+ for (l = overlay->priv->children; l != NULL; l = g_slist_next (l))
+ {
+ ContainerChild *child = (ContainerChild *)l->data;
+ GtkWidget *w;
+
+ if (child->is_animated)
+ {
+ w = gedit_theatrics_animated_widget_get_widget (GEDIT_THEATRICS_ANIMATED_WIDGET (child->child));
+ }
+ else
+ {
+ w = child->child;
+ }
+
+ if (w == widget)
+ {
+ child->x = x;
+ child->y = y;
+ }
+ }
+}
diff --git a/gedit/gedit-overlay.h b/gedit/gedit-overlay.h
new file mode 100644
index 0000000..bf9be4e
--- /dev/null
+++ b/gedit/gedit-overlay.h
@@ -0,0 +1,80 @@
+/*
+ * gedit-overlay.h
+ * This file is part of gedit
+ *
+ * Copyright (C) 2010 - Ignacio Casal Quinteiro
+ *
+ * gedit is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * gedit 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 gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifndef __GEDIT_OVERLAY_H__
+#define __GEDIT_OVERLAY_H__
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include "theatrics/gedit-theatrics-choreographer.h"
+
+G_BEGIN_DECLS
+
+#define GEDIT_TYPE_OVERLAY (gedit_overlay_get_type ())
+#define GEDIT_OVERLAY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_OVERLAY, GeditOverlay))
+#define GEDIT_OVERLAY_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_OVERLAY, GeditOverlay const))
+#define GEDIT_OVERLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GEDIT_TYPE_OVERLAY, GeditOverlayClass))
+#define GEDIT_IS_OVERLAY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEDIT_TYPE_OVERLAY))
+#define GEDIT_IS_OVERLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEDIT_TYPE_OVERLAY))
+#define GEDIT_OVERLAY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GEDIT_TYPE_OVERLAY, GeditOverlayClass))
+
+typedef struct _GeditOverlay GeditOverlay;
+typedef struct _GeditOverlayClass GeditOverlayClass;
+typedef struct _GeditOverlayPrivate GeditOverlayPrivate;
+
+struct _GeditOverlay
+{
+ GtkContainer parent;
+
+ GeditOverlayPrivate *priv;
+};
+
+struct _GeditOverlayClass
+{
+ GtkContainerClass parent_class;
+
+ void (* set_scroll_adjustments) (GeditOverlay *overlay,
+ GtkAdjustment *hadjustment,
+ GtkAdjustment *vadjustment);
+};
+
+GType gedit_overlay_get_type (void) G_GNUC_CONST;
+
+GtkWidget *gedit_overlay_new (GtkWidget *main_widget);
+
+void gedit_overlay_add_animated_widget (GeditOverlay *overlay,
+ GtkWidget *widget,
+ guint duration,
+ GeditTheatricsChoreographerEasing easing,
+ GeditTheatricsChoreographerBlocking blocking,
+ GtkOrientation orientation,
+ gint x,
+ gint y);
+
+void gedit_overlay_move_widget (GeditOverlay *container,
+ GtkWidget *widget,
+ gint x,
+ gint y);
+
+G_END_DECLS
+
+#endif /* __GEDIT_OVERLAY_H__ */
diff --git a/gedit/gedit-rounded-frame.c b/gedit/gedit-rounded-frame.c
new file mode 100644
index 0000000..c762021
--- /dev/null
+++ b/gedit/gedit-rounded-frame.c
@@ -0,0 +1,231 @@
+/*
+ * gedit-rounded-frame.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 2010 - Ignacio Casal Quinteiro
+ *
+ * Work based on Aaron Bockover <abockover novell com>
+ * Gabriel Burt <gburt novell com>
+ *
+ * gedit is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * gedit 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 gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#include "gedit-rounded-frame.h"
+#include "theatrics/gedit-theatrics-utils.h"
+
+
+#define GEDIT_ROUNDED_FRAME_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GEDIT_TYPE_ROUNDED_FRAME, GeditRoundedFramePrivate))
+
+struct _GeditRoundedFramePrivate
+{
+ GtkWidget *child;
+
+ GtkAllocation child_allocation;
+ guint frame_width;
+};
+
+G_DEFINE_TYPE (GeditRoundedFrame, gedit_rounded_frame, GTK_TYPE_BIN)
+
+static void
+gedit_rounded_frame_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (gedit_rounded_frame_parent_class)->finalize (object);
+}
+
+static void
+gedit_rounded_frame_size_request (GtkWidget *widget,
+ GtkRequisition *requisition)
+{
+ GeditRoundedFrame *frame = GEDIT_ROUNDED_FRAME (widget);
+ gint border_width;
+
+ if (frame->priv->child != NULL &&
+ gtk_widget_get_visible (frame->priv->child))
+ {
+ GtkRequisition child_requisition;
+
+ /* Add the child's width/height */
+ gtk_widget_size_request (frame->priv->child, &child_requisition);
+
+ requisition->width = MAX (0, child_requisition.width);
+ requisition->height = child_requisition.height;
+ }
+ else
+ {
+ requisition->width = 0;
+ requisition->height = 0;
+ }
+
+ /* Add the border */
+ border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
+ requisition->width += (border_width + frame->priv->frame_width) * 2;
+ requisition->height += (border_width + frame->priv->frame_width) * 2;
+}
+
+static void
+gedit_rounded_frame_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ GeditRoundedFrame *frame = GEDIT_ROUNDED_FRAME (widget);
+ GtkAllocation *child_allocation;
+ int border;
+
+ child_allocation = &frame->priv->child_allocation;
+
+ GTK_WIDGET_CLASS (gedit_rounded_frame_parent_class)->size_allocate (widget, allocation);
+
+ if (frame->priv->child == NULL ||
+ !gtk_widget_get_visible (frame->priv->child))
+ {
+ return;
+ }
+
+ border = gtk_container_get_border_width (GTK_CONTAINER (widget)) +
+ frame->priv->frame_width;
+ child_allocation->x = allocation->x + border;
+ child_allocation->y = allocation->y + border;
+ child_allocation->width = MAX (1, allocation->width - border * 2);
+ child_allocation->height = MAX (1, allocation->height - border * 2);
+
+ gtk_widget_size_allocate (frame->priv->child, child_allocation);
+}
+
+static void
+draw_frame (GeditRoundedFrame *frame,
+ cairo_t *cr,
+ GdkRectangle *area)
+{
+ GtkStyle *style;
+ GdkColor bg_color;
+ GdkColor border_color;
+
+ gedit_theatrics_utils_draw_round_rectangle (cr,
+ FALSE,
+ FALSE,
+ TRUE,
+ TRUE,
+ area->x,
+ area->y,
+ MIN (0.30 * area->width, 0.30 * area->height),
+ area->width,
+ area->height);
+
+ style = gtk_widget_get_style (GTK_WIDGET (frame));
+ bg_color = style->bg[GTK_STATE_NORMAL];
+ border_color = style->dark[GTK_STATE_ACTIVE];
+
+ gdk_cairo_set_source_color (cr, &bg_color);
+ cairo_fill_preserve (cr);
+
+ gdk_cairo_set_source_color (cr, &border_color);
+ cairo_set_line_width (cr, frame->priv->frame_width / 2);
+ cairo_stroke (cr);
+}
+
+static gboolean
+gedit_rounded_frame_expose_event (GtkWidget *widget,
+ GdkEventExpose *event)
+{
+ GeditRoundedFrame *frame = GEDIT_ROUNDED_FRAME (widget);
+ GdkRectangle area;
+ cairo_t *cr;
+
+ if (!gtk_widget_is_drawable (widget))
+ {
+ return FALSE;
+ }
+
+ cr = gdk_cairo_create (event->window);
+
+ area.x = frame->priv->child_allocation.x - frame->priv->frame_width;
+ area.y = frame->priv->child_allocation.y - 2 * frame->priv->frame_width - 1;
+ area.width = frame->priv->child_allocation.width + 2 * frame->priv->frame_width;
+ area.height = frame->priv->child_allocation.height + 3 * frame->priv->frame_width;
+
+ draw_frame (frame, cr, &area);
+
+ if (frame->priv->child != NULL)
+ {
+ gtk_container_propagate_expose (GTK_CONTAINER (frame),
+ frame->priv->child,
+ event);
+ }
+
+ cairo_destroy (cr);
+
+ return FALSE;
+}
+
+static void
+gedit_rounded_frame_add (GtkContainer *container,
+ GtkWidget *widget)
+{
+ GeditRoundedFrame *frame = GEDIT_ROUNDED_FRAME (container);
+
+ frame->priv->child = widget;
+
+ GTK_CONTAINER_CLASS (gedit_rounded_frame_parent_class)->add (container, widget);
+}
+
+static void
+gedit_rounded_frame_remove (GtkContainer *container,
+ GtkWidget *widget)
+{
+ GeditRoundedFrame *frame = GEDIT_ROUNDED_FRAME (container);
+
+ if (frame->priv->child == widget)
+ {
+ frame->priv->child = NULL;
+ }
+
+ GTK_CONTAINER_CLASS (gedit_rounded_frame_parent_class)->remove (container, widget);
+}
+
+static void
+gedit_rounded_frame_class_init (GeditRoundedFrameClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
+
+ object_class->finalize = gedit_rounded_frame_finalize;
+
+ widget_class->size_request = gedit_rounded_frame_size_request;
+ widget_class->size_allocate = gedit_rounded_frame_size_allocate;
+ widget_class->expose_event = gedit_rounded_frame_expose_event;
+
+ container_class->add = gedit_rounded_frame_add;
+ container_class->remove = gedit_rounded_frame_remove;
+
+ g_type_class_add_private (object_class, sizeof (GeditRoundedFramePrivate));
+}
+
+static void
+gedit_rounded_frame_init (GeditRoundedFrame *frame)
+{
+ frame->priv = GEDIT_ROUNDED_FRAME_GET_PRIVATE (frame);
+
+ frame->priv->frame_width = 3; /* Make it a prop */
+
+ gtk_widget_set_has_window (GTK_WIDGET (frame), FALSE);
+ gtk_widget_set_app_paintable (GTK_WIDGET (frame), FALSE);
+}
+
+GtkWidget *
+gedit_rounded_frame_new ()
+{
+ return GTK_WIDGET (g_object_new (GEDIT_TYPE_ROUNDED_FRAME, NULL));
+}
diff --git a/gedit/gedit-rounded-frame.h b/gedit/gedit-rounded-frame.h
new file mode 100644
index 0000000..9fce152
--- /dev/null
+++ b/gedit/gedit-rounded-frame.h
@@ -0,0 +1,61 @@
+/*
+ * gedit-rounded-frame.h
+ * This file is part of gedit
+ *
+ * Copyright (C) 2010 - Ignacio Casal Quinteiro
+ *
+ * gedit is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * gedit 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 gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifndef __GEDIT_ROUNDED_FRAME_H__
+#define __GEDIT_ROUNDED_FRAME_H__
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GEDIT_TYPE_ROUNDED_FRAME (gedit_rounded_frame_get_type ())
+#define GEDIT_ROUNDED_FRAME(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_ROUNDED_FRAME, GeditRoundedFrame))
+#define GEDIT_ROUNDED_FRAME_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_ROUNDED_FRAME, GeditRoundedFrame const))
+#define GEDIT_ROUNDED_FRAME_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GEDIT_TYPE_ROUNDED_FRAME, GeditRoundedFrameClass))
+#define GEDIT_IS_ROUNDED_FRAME(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEDIT_TYPE_ROUNDED_FRAME))
+#define GEDIT_IS_ROUNDED_FRAME_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEDIT_TYPE_ROUNDED_FRAME))
+#define GEDIT_ROUNDED_FRAME_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GEDIT_TYPE_ROUNDED_FRAME, GeditRoundedFrameClass))
+
+typedef struct _GeditRoundedFrame GeditRoundedFrame;
+typedef struct _GeditRoundedFrameClass GeditRoundedFrameClass;
+typedef struct _GeditRoundedFramePrivate GeditRoundedFramePrivate;
+
+struct _GeditRoundedFrame
+{
+ GtkBin parent;
+
+ GeditRoundedFramePrivate *priv;
+};
+
+struct _GeditRoundedFrameClass
+{
+ GtkBinClass parent_class;
+};
+
+GType gedit_rounded_frame_get_type (void) G_GNUC_CONST;
+
+GtkWidget *gedit_rounded_frame_new (void);
+
+G_END_DECLS
+
+#endif /* __GEDIT_ROUNDED_FRAME_H__ */
diff --git a/gedit/gedit-tab.c b/gedit/gedit-tab.c
index c6a5db2..245110e 100644
--- a/gedit/gedit-tab.c
+++ b/gedit/gedit-tab.c
@@ -2923,4 +2923,10 @@ gedit_tab_set_info_bar (GeditTab *tab,
set_info_bar (tab, info_bar);
}
+GtkWidget *
+_gedit_tab_get_view_frame (GeditTab *tab)
+{
+ return GTK_WIDGET (tab->priv->frame);
+}
+
/* ex:ts=8:noet: */
diff --git a/gedit/gedit-tab.h b/gedit/gedit-tab.h
index 1b45989..0f25d79 100644
--- a/gedit/gedit-tab.h
+++ b/gedit/gedit-tab.h
@@ -175,6 +175,7 @@ void _gedit_tab_mark_for_closing (GeditTab *tab);
gboolean _gedit_tab_can_close (GeditTab *tab);
+GtkWidget *_gedit_tab_get_view_frame (GeditTab *tab);
G_END_DECLS
diff --git a/gedit/gedit-view-frame.c b/gedit/gedit-view-frame.c
index 1c8ee7e..faa6f58 100644
--- a/gedit/gedit-view-frame.c
+++ b/gedit/gedit-view-frame.c
@@ -21,13 +21,59 @@
*/
#include "gedit-view-frame.h"
+#include "gedit-marshal.h"
+#include "gedit-debug.h"
+#include "gedit-utils.h"
+#include "gedit-overlay.h"
+#include "gedit-rounded-frame.h"
+#include <gdk/gdkkeysyms.h>
+#include <glib/gi18n.h>
+#include <stdlib.h>
+
+#define GEDIT_VIEW_FRAME_SEARCH_DIALOG_TIMEOUT (30*1000) /* 30 seconds */
+
+#define MIN_SEARCH_COMPLETION_KEY_LEN 3
#define GEDIT_VIEW_FRAME_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GEDIT_TYPE_VIEW_FRAME, GeditViewFramePrivate))
+typedef enum
+{
+ GOTO_LINE,
+ SEARCH
+} SearchMode;
+
struct _GeditViewFramePrivate
{
- GtkWidget *view;
+ GtkWidget *view;
+ GtkWidget *overlay;
+
+ SearchMode search_mode;
+ SearchMode request_search_mode;
+
+ GtkTextMark *start_mark;
+
+ /* used to restore the search state if an
+ * incremental search is cancelled
+ */
+ gchar *old_search_text;
+ guint old_search_flags;
+
+ /* used to remeber the state of the last
+ * incremental search (the document search
+ * state may be changed by the search dialog)
+ */
+ guint search_flags;
+
+ GtkWidget *search_widget;
+ GtkWidget *search_entry;
+
+ guint typeselect_flush_timeout;
+ glong view_scroll_event_id;
+ glong search_entry_focus_out_id;
+
+ guint disable_popdown : 1;
+ guint wrap_around : 1;
};
enum
@@ -37,15 +83,42 @@ enum
PROP_VIEW
};
+typedef enum
+{
+ GEDIT_SEARCH_ENTRY_NORMAL,
+ GEDIT_SEARCH_ENTRY_NOT_FOUND
+} GeditSearchEntryBgColor;
+
+/* The search entry completion is shared among all the views */
+GtkListStore *search_completion_model = NULL;
+
G_DEFINE_TYPE (GeditViewFrame, gedit_view_frame, GTK_TYPE_VBOX)
static void
gedit_view_frame_finalize (GObject *object)
{
+ GeditViewFrame *frame = GEDIT_VIEW_FRAME (object);
+
+ g_free (frame->priv->old_search_text);
+
G_OBJECT_CLASS (gedit_view_frame_parent_class)->finalize (object);
}
static void
+gedit_view_frame_dispose (GObject *object)
+{
+ GeditViewFrame *frame = GEDIT_VIEW_FRAME (object);
+
+ if (frame->priv->typeselect_flush_timeout != 0)
+ {
+ g_source_remove (frame->priv->typeselect_flush_timeout);
+ frame->priv->typeselect_flush_timeout = 0;
+ }
+
+ G_OBJECT_CLASS (gedit_view_frame_parent_class)->dispose (object);
+}
+
+static void
gedit_view_frame_get_property (GObject *object,
guint prop_id,
GValue *value,
@@ -70,11 +143,1124 @@ gedit_view_frame_get_property (GObject *object,
}
static void
+hide_search_widget (GeditViewFrame *frame,
+ gboolean cancel)
+{
+ GtkTextBuffer *buffer;
+
+ if (frame->priv->disable_popdown)
+ {
+ return;
+ }
+
+ if (frame->priv->view_scroll_event_id != 0)
+ {
+ g_signal_handler_disconnect (frame->priv->view,
+ frame->priv->view_scroll_event_id);
+ frame->priv->view_scroll_event_id = 0;
+ }
+
+ if (frame->priv->search_entry_focus_out_id != 0)
+ {
+ g_signal_handler_disconnect (frame->priv->search_entry,
+ frame->priv->search_entry_focus_out_id);
+ frame->priv->search_entry_focus_out_id = 0;
+ }
+
+ if (frame->priv->typeselect_flush_timeout != 0)
+ {
+ g_source_remove (frame->priv->typeselect_flush_timeout);
+ frame->priv->typeselect_flush_timeout = 0;
+ }
+
+ gtk_widget_destroy (frame->priv->search_widget);
+ frame->priv->search_widget = NULL;
+
+ if (cancel)
+ {
+ GtkTextBuffer *buffer;
+ GtkTextIter iter;
+
+ buffer = GTK_TEXT_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (frame->priv->view)));
+ gtk_text_buffer_get_iter_at_mark (buffer, &iter,
+ frame->priv->start_mark);
+ gtk_text_buffer_place_cursor (buffer, &iter);
+
+ gedit_view_scroll_to_cursor (GEDIT_VIEW (frame->priv->view));
+ }
+
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (frame->priv->view));
+ gtk_text_buffer_delete_mark (buffer, frame->priv->start_mark);
+
+ /* Make sure the view is the one who has the focus when we destroy
+ the search widget */
+ gtk_widget_grab_focus (frame->priv->view);
+}
+
+static void
+add_search_completion_entry (const gchar *str)
+{
+ gchar *text;
+ gboolean valid;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ if (str == NULL)
+ return;
+
+ text = gedit_utils_unescape_search_text (str);
+
+ if (g_utf8_strlen (text, -1) < MIN_SEARCH_COMPLETION_KEY_LEN)
+ {
+ g_free (text);
+ return;
+ }
+
+ g_return_if_fail (GTK_IS_TREE_MODEL (search_completion_model));
+
+ model = GTK_TREE_MODEL (search_completion_model);
+
+ /* Get the first iter in the list */
+ valid = gtk_tree_model_get_iter_first (model, &iter);
+
+ while (valid)
+ {
+ /* Walk through the list, reading each row */
+ gchar *str_data;
+
+ gtk_tree_model_get (model,
+ &iter,
+ 0,
+ &str_data,
+ -1);
+
+ if (strcmp (text, str_data) == 0)
+ {
+ g_free (text);
+ g_free (str_data);
+ gtk_list_store_move_after (GTK_LIST_STORE (model),
+ &iter,
+ NULL);
+
+ return;
+ }
+
+ g_free (str_data);
+
+ valid = gtk_tree_model_iter_next (model, &iter);
+ }
+
+ gtk_list_store_prepend (GTK_LIST_STORE (model), &iter);
+ gtk_list_store_set (GTK_LIST_STORE (model),
+ &iter,
+ 0,
+ text,
+ -1);
+
+ g_free (text);
+}
+
+static gboolean
+search_entry_flush_timeout (GeditViewFrame *frame)
+{
+ GDK_THREADS_ENTER ();
+
+ frame->priv->typeselect_flush_timeout = 0;
+ hide_search_widget (frame, FALSE);
+
+ GDK_THREADS_LEAVE ();
+
+ return FALSE;
+}
+
+static void
+set_entry_background (GtkWidget *entry,
+ GeditSearchEntryBgColor col)
+{
+ if (col == GEDIT_SEARCH_ENTRY_NOT_FOUND)
+ {
+ GdkColor red;
+ GdkColor white;
+
+ /* FIXME: a11y and theme */
+
+ gdk_color_parse ("#FF6666", &red);
+ gdk_color_parse ("white", &white);
+
+ gtk_widget_modify_base (entry,
+ GTK_STATE_NORMAL,
+ &red);
+ gtk_widget_modify_text (entry,
+ GTK_STATE_NORMAL,
+ &white);
+ }
+ else /* reset */
+ {
+ gtk_widget_modify_base (entry,
+ GTK_STATE_NORMAL,
+ NULL);
+ gtk_widget_modify_text (entry,
+ GTK_STATE_NORMAL,
+ NULL);
+ }
+}
+
+static gboolean
+run_search (GeditViewFrame *frame,
+ const gchar *entry_text,
+ gboolean search_backward,
+ gboolean wrap_around,
+ gboolean typing)
+{
+ GtkTextIter start_iter;
+ GtkTextIter match_start;
+ GtkTextIter match_end;
+ gboolean found = FALSE;
+ GeditDocument *doc;
+
+ g_return_val_if_fail (frame->priv->search_mode == SEARCH, FALSE);
+
+ doc = gedit_view_frame_get_document (frame);
+
+ gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (doc),
+ &start_iter,
+ frame->priv->start_mark);
+
+ if (*entry_text != '\0')
+ {
+ if (!search_backward)
+ {
+ if (!typing)
+ {
+ /* forward and _NOT_ typing */
+ gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (doc),
+ &start_iter,
+ &match_end);
+
+ gtk_text_iter_order (&match_end, &start_iter);
+ }
+
+ /* run search */
+ found = gedit_document_search_forward (doc,
+ &start_iter,
+ NULL,
+ &match_start,
+ &match_end);
+ }
+ else if (!typing)
+ {
+ /* backward and not typing */
+ gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (doc),
+ &start_iter,
+ &match_end);
+
+ /* run search */
+ found = gedit_document_search_backward (doc,
+ NULL,
+ &start_iter,
+ &match_start,
+ &match_end);
+ }
+ else
+ {
+ /* backward (while typing) */
+ g_return_val_if_reached (FALSE);
+ }
+
+ if (!found && wrap_around)
+ {
+ if (!search_backward)
+ {
+ found = gedit_document_search_forward (doc,
+ NULL,
+ NULL, /* FIXME: set the end_inter */
+ &match_start,
+ &match_end);
+ }
+ else
+ {
+ found = gedit_document_search_backward (doc,
+ NULL, /* FIXME: set the start_inter */
+ NULL,
+ &match_start,
+ &match_end);
+ }
+ }
+ }
+ else
+ {
+ gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (doc),
+ &start_iter,
+ NULL);
+ }
+
+ if (found)
+ {
+ gtk_text_buffer_place_cursor (GTK_TEXT_BUFFER (doc),
+ &match_start);
+
+ gtk_text_buffer_move_mark_by_name (GTK_TEXT_BUFFER (doc),
+ "selection_bound", &match_end);
+ }
+ else if (typing)
+ {
+ gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (doc),
+ &start_iter,
+ frame->priv->start_mark);
+ gtk_text_buffer_place_cursor (GTK_TEXT_BUFFER (doc),
+ &start_iter);
+ }
+
+ if (found || (*entry_text == '\0'))
+ {
+ gedit_view_scroll_to_cursor (GEDIT_VIEW (frame->priv->view));
+
+ set_entry_background (frame->priv->search_entry,
+ GEDIT_SEARCH_ENTRY_NORMAL);
+ }
+ else
+ {
+ set_entry_background (frame->priv->search_entry,
+ GEDIT_SEARCH_ENTRY_NOT_FOUND);
+ }
+
+ return found;
+}
+
+static void
+search_again (GeditViewFrame *frame,
+ gboolean search_backward)
+{
+ const gchar *entry_text;
+
+ g_return_if_fail (frame->priv->search_mode == SEARCH);
+
+ /* SEARCH mode */
+ /* renew the flush timeout */
+ if (frame->priv->typeselect_flush_timeout != 0)
+ {
+ g_source_remove (frame->priv->typeselect_flush_timeout);
+ frame->priv->typeselect_flush_timeout =
+ g_timeout_add (GEDIT_VIEW_FRAME_SEARCH_DIALOG_TIMEOUT,
+ (GSourceFunc)search_entry_flush_timeout,
+ frame);
+ }
+
+ entry_text = gtk_entry_get_text (GTK_ENTRY (frame->priv->search_entry));
+
+ add_search_completion_entry (entry_text);
+
+ run_search (frame,
+ entry_text,
+ search_backward,
+ frame->priv->wrap_around,
+ FALSE);
+}
+
+static gboolean
+search_widget_scroll_event (GtkWidget *widget,
+ GdkEventScroll *event,
+ GeditViewFrame *frame)
+{
+ gboolean retval = FALSE;
+
+ if (frame->priv->search_mode == GOTO_LINE)
+ return retval;
+
+ /* SEARCH mode */
+ if (event->direction == GDK_SCROLL_UP)
+ {
+ search_again (frame, TRUE);
+ retval = TRUE;
+ }
+ else if (event->direction == GDK_SCROLL_DOWN)
+ {
+ search_again (frame, FALSE);
+ retval = TRUE;
+ }
+
+ return retval;
+}
+
+static gboolean
+search_widget_key_press_event (GtkWidget *widget,
+ GdkEventKey *event,
+ GeditViewFrame *frame)
+{
+ gboolean retval = FALSE;
+ guint modifiers;
+
+ modifiers = gtk_accelerator_get_default_mod_mask ();
+
+ /* Close window */
+ if (event->keyval == GDK_Tab)
+ {
+ hide_search_widget (frame, FALSE);
+ retval = TRUE;
+ }
+
+ /* Close window and cancel the search */
+ if (event->keyval == GDK_Escape)
+ {
+ if (frame->priv->search_mode == SEARCH)
+ {
+ GeditDocument *doc;
+
+ /* restore document search so that Find Next does the right thing */
+ doc = gedit_view_frame_get_document (frame);
+ gedit_document_set_search_text (doc,
+ frame->priv->old_search_text,
+ frame->priv->old_search_flags);
+ }
+
+ hide_search_widget (frame, TRUE);
+ retval = TRUE;
+ }
+
+ if (frame->priv->search_mode == GOTO_LINE)
+ return retval;
+
+ /* SEARCH mode */
+
+ /* select previous matching iter */
+ if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up)
+ {
+ search_again (frame, TRUE);
+ retval = TRUE;
+ }
+
+ if (((event->state & modifiers) == (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) &&
+ (event->keyval == GDK_g || event->keyval == GDK_G))
+ {
+ search_again (frame, TRUE);
+ retval = TRUE;
+ }
+
+ /* select next matching iter */
+ if (event->keyval == GDK_Down || event->keyval == GDK_KP_Down)
+ {
+ search_again (frame, FALSE);
+ retval = TRUE;
+ }
+
+ if (((event->state & modifiers) == GDK_CONTROL_MASK) &&
+ (event->keyval == GDK_g || event->keyval == GDK_G))
+ {
+ search_again (frame, FALSE);
+ retval = TRUE;
+ }
+
+ return retval;
+}
+
+static void
+wrap_around_menu_item_toggled (GtkCheckMenuItem *checkmenuitem,
+ GeditViewFrame *frame)
+{
+ frame->priv->wrap_around = gtk_check_menu_item_get_active (checkmenuitem);
+}
+
+static void
+match_entire_word_menu_item_toggled (GtkCheckMenuItem *checkmenuitem,
+ GeditViewFrame *frame)
+{
+ GEDIT_SEARCH_SET_ENTIRE_WORD (frame->priv->search_flags,
+ gtk_check_menu_item_get_active (checkmenuitem));
+}
+
+static void
+match_case_menu_item_toggled (GtkCheckMenuItem *checkmenuitem,
+ GeditViewFrame *frame)
+{
+ GEDIT_SEARCH_SET_CASE_SENSITIVE (frame->priv->search_flags,
+ gtk_check_menu_item_get_active (checkmenuitem));
+}
+
+static void
+add_popup_menu_items (GtkWidget *menu,
+ GeditViewFrame *frame)
+{
+ GtkWidget *menu_item;
+
+ /* create "Wrap Around" menu item. */
+ menu_item = gtk_check_menu_item_new_with_mnemonic (_("_Wrap Around"));
+ g_signal_connect (G_OBJECT (menu_item), "toggled",
+ G_CALLBACK (wrap_around_menu_item_toggled),
+ frame);
+ gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
+ gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item),
+ frame->priv->wrap_around);
+ gtk_widget_show (menu_item);
+
+ /* create "Match Entire Word Only" menu item. */
+ menu_item = gtk_check_menu_item_new_with_mnemonic (_("Match _Entire Word Only"));
+ g_signal_connect (G_OBJECT (menu_item), "toggled",
+ G_CALLBACK (match_entire_word_menu_item_toggled),
+ frame);
+ gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
+ gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item),
+ GEDIT_SEARCH_IS_ENTIRE_WORD (frame->priv->search_flags));
+ gtk_widget_show (menu_item);
+
+ /* create "Match Case" menu item. */
+ menu_item = gtk_check_menu_item_new_with_mnemonic (_("_Match Case"));
+ g_signal_connect (G_OBJECT (menu_item), "toggled",
+ G_CALLBACK (match_case_menu_item_toggled),
+ frame);
+ gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
+ gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item),
+ GEDIT_SEARCH_IS_CASE_SENSITIVE (frame->priv->search_flags));
+ gtk_widget_show (menu_item);
+}
+
+static gboolean
+real_search_enable_popdown (gpointer data)
+{
+ GeditViewFrame *frame = GEDIT_VIEW_FRAME (data);
+
+ GDK_THREADS_ENTER ();
+
+ frame->priv->disable_popdown = FALSE;
+
+ GDK_THREADS_LEAVE ();
+
+ return FALSE;
+}
+
+static void
+search_enable_popdown (GtkWidget *widget,
+ GeditViewFrame *frame)
+{
+ g_timeout_add (200, real_search_enable_popdown, frame);
+
+ /* renew the flush timeout */
+ if (frame->priv->typeselect_flush_timeout != 0)
+ g_source_remove (frame->priv->typeselect_flush_timeout);
+
+ frame->priv->typeselect_flush_timeout =
+ g_timeout_add (GEDIT_VIEW_FRAME_SEARCH_DIALOG_TIMEOUT,
+ (GSourceFunc)search_entry_flush_timeout,
+ frame);
+}
+
+static void
+search_entry_populate_popup (GtkEntry *entry,
+ GtkMenu *menu,
+ GeditViewFrame *frame)
+{
+ GtkWidget *menu_item;
+
+ frame->priv->disable_popdown = TRUE;
+ g_signal_connect (menu, "hide",
+ G_CALLBACK (search_enable_popdown), frame);
+
+ if (frame->priv->search_mode == GOTO_LINE)
+ return;
+
+ /* separator */
+ menu_item = gtk_menu_item_new ();
+ gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
+ gtk_widget_show (menu_item);
+
+ add_popup_menu_items (GTK_WIDGET (menu), frame);
+}
+
+static void
+search_entry_icon_release (GtkEntry *entry,
+ GtkEntryIconPosition icon_pos,
+ GdkEventButton *event,
+ GeditViewFrame *frame)
+{
+ GtkWidget *menu;
+
+ if (frame->priv->search_mode == GOTO_LINE ||
+ icon_pos != GTK_ENTRY_ICON_PRIMARY)
+ return;
+
+ menu = gtk_menu_new ();
+ gtk_widget_show (menu);
+
+ frame->priv->disable_popdown = TRUE;
+ g_signal_connect (menu, "hide",
+ G_CALLBACK (search_enable_popdown), frame);
+
+ add_popup_menu_items (menu, frame);
+
+ gtk_menu_popup (GTK_MENU (menu),
+ NULL, NULL,
+ NULL, NULL,
+ event->button, event->time);
+}
+
+static void
+search_entry_activate (GtkEntry *entry,
+ GeditViewFrame *frame)
+{
+ hide_search_widget (frame, FALSE);
+}
+
+static void
+search_entry_insert_text (GtkEditable *editable,
+ const gchar *text,
+ gint length,
+ gint *position,
+ GeditViewFrame *frame)
+{
+ if (frame->priv->search_mode == GOTO_LINE)
+ {
+ gunichar c;
+ const gchar *p;
+ const gchar *end;
+ const gchar *next;
+
+ p = text;
+ end = text + length;
+
+ if (p == end)
+ return;
+
+ c = g_utf8_get_char (p);
+
+ if (((c == '-' || c == '+') && *position == 0) ||
+ (c == ':' && *position != 0))
+ {
+ gchar *s = NULL;
+
+ if (c == ':')
+ {
+ s = gtk_editable_get_chars (editable, 0, -1);
+ s = g_utf8_strchr (s, -1, ':');
+ }
+
+ if (s == NULL || s == p)
+ {
+ next = g_utf8_next_char (p);
+ p = next;
+ }
+
+ g_free (s);
+ }
+
+ while (p != end)
+ {
+ next = g_utf8_next_char (p);
+
+ c = g_utf8_get_char (p);
+
+ if (!g_unichar_isdigit (c))
+ {
+ g_signal_stop_emission_by_name (editable, "insert_text");
+ gtk_widget_error_bell (frame->priv->search_entry);
+ break;
+ }
+
+ p = next;
+ }
+ }
+ else
+ {
+ /* SEARCH mode */
+ static gboolean insert_text = FALSE;
+ gchar *escaped_text;
+ gint new_len;
+
+ gedit_debug_message (DEBUG_SEARCH, "Text: %s", text);
+
+ /* To avoid recursive behavior */
+ if (insert_text)
+ return;
+
+ escaped_text = gedit_utils_escape_search_text (text);
+
+ gedit_debug_message (DEBUG_SEARCH, "Escaped Text: %s", escaped_text);
+
+ new_len = strlen (escaped_text);
+
+ if (new_len == length)
+ {
+ g_free (escaped_text);
+ return;
+ }
+
+ insert_text = TRUE;
+
+ g_signal_stop_emission_by_name (editable, "insert_text");
+
+ gtk_editable_insert_text (editable, escaped_text, new_len, position);
+
+ insert_text = FALSE;
+
+ g_free (escaped_text);
+ }
+}
+
+static gboolean
+completion_func (GtkEntryCompletion *completion,
+ const gchar *key,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ gchar *item = NULL;
+ gboolean ret = FALSE;
+ GtkTreeModel *model;
+ GeditViewFramePrivate *priv = GEDIT_VIEW_FRAME (data)->priv;
+ const gchar *real_key;
+
+ if (priv->search_mode == GOTO_LINE)
+ return FALSE;
+
+ real_key = gtk_entry_get_text (GTK_ENTRY (gtk_entry_completion_get_entry (completion)));
+
+ if (g_utf8_strlen (real_key, -1) <= MIN_SEARCH_COMPLETION_KEY_LEN)
+ return FALSE;
+
+ model = gtk_entry_completion_get_model (completion);
+ g_return_val_if_fail (gtk_tree_model_get_column_type (model, 0) == G_TYPE_STRING,
+ FALSE);
+
+ gtk_tree_model_get (model,
+ iter,
+ 0,
+ &item,
+ -1);
+
+ if (item == NULL)
+ return FALSE;
+
+ if (GEDIT_SEARCH_IS_CASE_SENSITIVE (priv->search_flags))
+ {
+ if (!strncmp (real_key, item, strlen (real_key)))
+ ret = TRUE;
+ }
+ else
+ {
+ gchar *normalized_string;
+ gchar *case_normalized_string;
+
+ normalized_string = g_utf8_normalize (item, -1, G_NORMALIZE_ALL);
+ case_normalized_string = g_utf8_casefold (normalized_string, -1);
+
+ if (!strncmp (key, case_normalized_string, strlen (key)))
+ ret = TRUE;
+
+ g_free (normalized_string);
+ g_free (case_normalized_string);
+ }
+
+ g_free (item);
+
+ return ret;
+}
+
+static void
+customize_for_search_mode (GeditViewFrame *frame)
+{
+ if (frame->priv->search_mode == SEARCH)
+ {
+ gtk_entry_set_icon_from_stock (GTK_ENTRY (frame->priv->search_entry),
+ GTK_ENTRY_ICON_PRIMARY,
+ GTK_STOCK_FIND);
+
+ gtk_widget_set_tooltip_text (frame->priv->search_entry,
+ _("String you want to search for"));
+ }
+ else
+ {
+ gtk_entry_set_icon_from_stock (GTK_ENTRY (frame->priv->search_entry),
+ GTK_ENTRY_ICON_PRIMARY,
+ GTK_STOCK_JUMP_TO);
+
+ gtk_widget_set_tooltip_text (frame->priv->search_entry,
+ _("Line you want to move the cursor to"));
+ }
+}
+
+static void
+search_init (GtkWidget *entry,
+ GeditViewFrame *frame)
+{
+ GeditDocument *doc;
+ const gchar *entry_text;
+
+ /* renew the flush timeout */
+ if (frame->priv->typeselect_flush_timeout != 0)
+ {
+ g_source_remove (frame->priv->typeselect_flush_timeout);
+ frame->priv->typeselect_flush_timeout =
+ g_timeout_add (GEDIT_VIEW_FRAME_SEARCH_DIALOG_TIMEOUT,
+ (GSourceFunc)search_entry_flush_timeout,
+ frame);
+ }
+
+ doc = gedit_view_frame_get_document (frame);
+
+ entry_text = gtk_entry_get_text (GTK_ENTRY (entry));
+
+ if (frame->priv->search_mode == SEARCH)
+ {
+ gchar *search_text;
+ guint search_flags;
+
+ search_text = gedit_document_get_search_text (doc, &search_flags);
+
+ if ((search_text == NULL) ||
+ (strcmp (search_text, entry_text) != 0) ||
+ search_flags != frame->priv->search_flags)
+ {
+ gedit_document_set_search_text (doc,
+ entry_text,
+ frame->priv->search_flags);
+ }
+
+ g_free (search_text);
+
+ run_search (frame,
+ entry_text,
+ FALSE,
+ frame->priv->wrap_around,
+ TRUE);
+ }
+ else
+ {
+ if (*entry_text != '\0')
+ {
+ gboolean moved, moved_offset;
+ gint line;
+ gint offset_line = 0;
+ gint line_offset = 0;
+ gchar **split_text = NULL;
+ const gchar *text;
+ GtkTextIter iter;
+
+ gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (doc),
+ &iter,
+ frame->priv->start_mark);
+
+ split_text = g_strsplit (entry_text, ":", -1);
+
+ if (g_strv_length (split_text) > 1)
+ {
+ text = split_text[0];
+ }
+ else
+ {
+ text = entry_text;
+ }
+
+ if (*text == '-')
+ {
+ gint cur_line = gtk_text_iter_get_line (&iter);
+
+ if (*(text + 1) != '\0')
+ offset_line = MAX (atoi (text + 1), 0);
+
+ line = MAX (cur_line - offset_line, 0);
+ }
+ else if (*entry_text == '+')
+ {
+ gint cur_line = gtk_text_iter_get_line (&iter);
+
+ if (*(text + 1) != '\0')
+ offset_line = MAX (atoi (text + 1), 0);
+
+ line = cur_line + offset_line;
+ }
+ else
+ {
+ line = MAX (atoi (text) - 1, 0);
+ }
+
+ if (split_text[1] != NULL)
+ {
+ line_offset = atoi (split_text[1]);
+ }
+
+ g_strfreev (split_text);
+
+ moved = gedit_document_goto_line (doc, line);
+ moved_offset = gedit_document_goto_line_offset (doc, line,
+ line_offset);
+
+ gedit_view_scroll_to_cursor (GEDIT_VIEW (frame->priv->view));
+
+ if (!moved || !moved_offset)
+ {
+ set_entry_background (frame->priv->search_entry,
+ GEDIT_SEARCH_ENTRY_NOT_FOUND);
+ }
+ else
+ {
+ set_entry_background (frame->priv->search_entry,
+ GEDIT_SEARCH_ENTRY_NORMAL);
+ }
+ }
+ }
+}
+
+static gboolean
+search_entry_focus_out_event (GtkWidget *widget,
+ GdkEventFocus *event,
+ GeditViewFrame *frame)
+{
+ /* hide interactive search dialog */
+ hide_search_widget (frame, FALSE);
+
+ return FALSE;
+}
+
+static GtkWidget *
+create_search_widget (GeditViewFrame *frame)
+{
+ GtkWidget *search_widget;
+ GtkWidget *vbox;
+ GtkEntryCompletion *completion;
+
+ search_widget = gedit_rounded_frame_new ();
+ gtk_widget_show (search_widget);
+
+ g_signal_connect (search_widget, "key-press-event",
+ G_CALLBACK (search_widget_key_press_event),
+ frame);
+ g_signal_connect (search_widget, "scroll-event",
+ G_CALLBACK (search_widget_scroll_event),
+ frame);
+ /* Manage the scroll also for the view */
+ frame->priv->view_scroll_event_id =
+ g_signal_connect (frame->priv->view, "scroll-event",
+ G_CALLBACK (search_widget_scroll_event),
+ frame);
+
+ vbox = gtk_vbox_new (FALSE, 0);
+ gtk_widget_show (vbox);
+ gtk_container_add (GTK_CONTAINER (search_widget), vbox);
+ gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
+
+ /* add entry */
+ frame->priv->search_entry = gtk_entry_new ();
+ gtk_widget_show (frame->priv->search_entry);
+
+ g_signal_connect (frame->priv->search_entry, "populate-popup",
+ G_CALLBACK (search_entry_populate_popup),
+ frame);
+ g_signal_connect (frame->priv->search_entry, "icon-release",
+ G_CALLBACK (search_entry_icon_release),
+ frame);
+ g_signal_connect (frame->priv->search_entry, "activate",
+ G_CALLBACK (search_entry_activate),
+ frame);
+ g_signal_connect (frame->priv->search_entry, "insert_text",
+ G_CALLBACK (search_entry_insert_text),
+ frame);
+ g_signal_connect (frame->priv->search_entry, "changed",
+ G_CALLBACK (search_init),
+ frame);
+ frame->priv->search_entry_focus_out_id =
+ g_signal_connect (frame->priv->search_entry, "focus-out-event",
+ G_CALLBACK (search_entry_focus_out_event),
+ frame);
+
+ gtk_container_add (GTK_CONTAINER (vbox),
+ frame->priv->search_entry);
+
+ if (search_completion_model == NULL)
+ {
+ /* Create a tree model and use it as the completion model */
+ search_completion_model = gtk_list_store_new (1, G_TYPE_STRING);
+ }
+
+ /* Create the completion object for the search entry */
+ completion = gtk_entry_completion_new ();
+ gtk_entry_completion_set_model (completion,
+ GTK_TREE_MODEL (search_completion_model));
+
+ /* Use model column 0 as the text column */
+ gtk_entry_completion_set_text_column (completion, 0);
+
+ gtk_entry_completion_set_minimum_key_length (completion,
+ MIN_SEARCH_COMPLETION_KEY_LEN);
+
+ gtk_entry_completion_set_popup_completion (completion, FALSE);
+ gtk_entry_completion_set_inline_completion (completion, TRUE);
+
+ gtk_entry_completion_set_match_func (completion,
+ completion_func,
+ frame,
+ NULL);
+
+ /* Assign the completion to the entry */
+ gtk_entry_set_completion (GTK_ENTRY (frame->priv->search_entry),
+ completion);
+ g_object_unref (completion);
+
+ customize_for_search_mode (frame);
+
+ return search_widget;
+}
+
+static gboolean
+get_selected_text (GtkTextBuffer *doc, gchar **selected_text, gint *len)
+{
+ GtkTextIter start, end;
+
+ g_return_val_if_fail (selected_text != NULL, FALSE);
+ g_return_val_if_fail (*selected_text == NULL, FALSE);
+
+ if (!gtk_text_buffer_get_selection_bounds (doc, &start, &end))
+ {
+ if (len != NULL)
+ len = 0;
+
+ return FALSE;
+ }
+
+ *selected_text = gtk_text_buffer_get_slice (doc, &start, &end, TRUE);
+
+ if (len != NULL)
+ *len = g_utf8_strlen (*selected_text, -1);
+
+ return TRUE;
+}
+
+static void
+init_search_entry (GeditViewFrame *frame)
+{
+ GtkTextBuffer *buffer;
+
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (frame->priv->view));
+
+ if (frame->priv->search_mode == GOTO_LINE)
+ {
+ gint line;
+ gchar *line_str;
+ GtkTextIter iter;
+
+ gtk_text_buffer_get_iter_at_mark (buffer,
+ &iter,
+ frame->priv->start_mark);
+
+ line = gtk_text_iter_get_line (&iter);
+
+ line_str = g_strdup_printf ("%d", line + 1);
+
+ gtk_entry_set_text (GTK_ENTRY (frame->priv->search_entry),
+ line_str);
+
+ g_free (line_str);
+
+ return;
+ }
+ else
+ {
+ /* SEARCH mode */
+ gboolean selection_exists;
+ gchar *find_text = NULL;
+ gchar *old_find_text;
+ guint old_find_flags = 0;
+ gint sel_len = 0;
+
+ g_free (frame->priv->old_search_text);
+
+ old_find_text = gedit_document_get_search_text (GEDIT_DOCUMENT (buffer),
+ &old_find_flags);
+ if (old_find_text != NULL)
+ {
+ frame->priv->old_search_text = old_find_text;
+ add_search_completion_entry (old_find_text);
+ }
+
+ if (old_find_flags != 0)
+ {
+ frame->priv->old_search_flags = old_find_flags;
+ }
+
+ selection_exists = get_selected_text (buffer,
+ &find_text,
+ &sel_len);
+
+ if (selection_exists && (find_text != NULL) && (sel_len <= 160))
+ {
+ gtk_entry_set_text (GTK_ENTRY (frame->priv->search_entry),
+ find_text);
+ }
+ else
+ {
+ gtk_entry_set_text (GTK_ENTRY (frame->priv->search_entry),
+ "");
+ }
+
+ g_free (find_text);
+ }
+}
+
+static gboolean
+start_interactive_search_real (GeditViewFrame *frame)
+{
+ GtkTextBuffer *buffer;
+ GtkTextMark *mark;
+ GtkTextIter iter;
+
+ /* FIXME: it enters here twice, why? */
+
+ if ((frame->priv->search_widget != NULL) &&
+ gtk_widget_get_visible (frame->priv->search_widget))
+ {
+ if (frame->priv->search_mode != frame->priv->request_search_mode)
+ {
+ hide_search_widget (frame, TRUE);
+ }
+ else
+ {
+ return TRUE;
+ }
+ }
+
+ frame->priv->search_mode = frame->priv->request_search_mode;
+
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (frame->priv->view));
+
+ if (frame->priv->search_mode == SEARCH)
+ {
+ mark = gtk_text_buffer_get_selection_bound (buffer);
+ }
+ else
+ {
+ mark = gtk_text_buffer_get_insert (buffer);
+ }
+
+ gtk_text_buffer_get_iter_at_mark (buffer, &iter, mark);
+ frame->priv->start_mark = gtk_text_buffer_create_mark (buffer, NULL,
+ &iter, FALSE);
+
+ frame->priv->search_widget = create_search_widget (frame);
+
+ gedit_overlay_add_animated_widget (GEDIT_OVERLAY (frame->priv->overlay),
+ frame->priv->search_widget,
+ 300,
+ GEDIT_THEATRICS_CHOREOGRAPHER_EASING_EXPONENTIAL_IN_OUT,
+ GEDIT_THEATRICS_CHOREOGRAPHER_BLOCKING_DOWNSTAGE,
+ GTK_ORIENTATION_VERTICAL,
+ 0, 0);
+
+ init_search_entry (frame);
+
+ frame->priv->typeselect_flush_timeout =
+ g_timeout_add (GEDIT_VIEW_FRAME_SEARCH_DIALOG_TIMEOUT,
+ (GSourceFunc) search_entry_flush_timeout,
+ frame);
+
+ /* We need to grab the focus after the widget has been added */
+ gtk_widget_grab_focus (frame->priv->search_entry);
+
+ return TRUE;
+}
+
+static void
gedit_view_frame_class_init (GeditViewFrameClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = gedit_view_frame_finalize;
+ object_class->dispose = gedit_view_frame_dispose;
object_class->get_property = gedit_view_frame_get_property;
g_object_class_install_property (object_class, PROP_DOCUMENT,
@@ -109,6 +1295,42 @@ view_frame_mount_operation_factory (GeditDocument *doc,
}
static void
+on_view_size_allocate (GeditView *view,
+ GtkAllocation *allocation,
+ GeditViewFrame *frame)
+{
+ if (frame->priv->search_widget != NULL)
+ {
+ GtkAllocation widget_alloc;
+
+ gtk_widget_get_allocation (frame->priv->search_widget,
+ &widget_alloc);
+ gedit_overlay_move_widget (GEDIT_OVERLAY (frame->priv->overlay),
+ frame->priv->search_widget,
+ allocation->width - widget_alloc.width - 8,
+ 0);
+ }
+}
+
+static gboolean
+on_start_interactive_search (GeditView *view,
+ GeditViewFrame *frame)
+{
+ frame->priv->request_search_mode = SEARCH;
+
+ return start_interactive_search_real (frame);
+}
+
+static gboolean
+on_start_interactive_goto_line (GeditView *view,
+ GeditViewFrame *frame)
+{
+ frame->priv->request_search_mode = GOTO_LINE;
+
+ return start_interactive_search_real (frame);
+}
+
+static void
gedit_view_frame_init (GeditViewFrame *frame)
{
GeditDocument *doc;
@@ -116,6 +1338,9 @@ gedit_view_frame_init (GeditViewFrame *frame)
frame->priv = GEDIT_VIEW_FRAME_GET_PRIVATE (frame);
+ frame->priv->typeselect_flush_timeout = 0;
+ frame->priv->wrap_around = TRUE;
+
doc = gedit_document_new ();
_gedit_document_set_mount_operation_factory (doc,
@@ -127,14 +1352,34 @@ gedit_view_frame_init (GeditViewFrame *frame)
g_object_unref (doc);
+ /* TODO: connect it when the search widget exists */
+ g_signal_connect_after (frame->priv->view,
+ "size-allocate",
+ G_CALLBACK (on_view_size_allocate),
+ frame);
+
+ g_signal_connect (frame->priv->view,
+ "start-interactive-search",
+ G_CALLBACK (on_start_interactive_search),
+ frame);
+
+ g_signal_connect (frame->priv->view,
+ "start-interactive-goto-line",
+ G_CALLBACK (on_start_interactive_goto_line),
+ frame);
+
+ frame->priv->overlay = gedit_overlay_new (frame->priv->view);
+ gtk_widget_show (frame->priv->overlay);
+
/* Create the scrolled window */
sw = gtk_scrolled_window_new (NULL, NULL);
+ gtk_container_add (GTK_CONTAINER (sw), frame->priv->overlay);
+
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
- gtk_container_add (GTK_CONTAINER (sw), frame->priv->view);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
GTK_SHADOW_IN);
gtk_widget_show (sw);
diff --git a/gedit/gedit-view.c b/gedit/gedit-view.c
index 4eba9b7..0cebb41 100644
--- a/gedit/gedit-view.c
+++ b/gedit/gedit-view.c
@@ -52,9 +52,6 @@
#include "gedit-app.h"
#define GEDIT_VIEW_SCROLL_MARGIN 0.02
-#define GEDIT_VIEW_SEARCH_DIALOG_TIMEOUT (30*1000) /* 30 seconds */
-
-#define MIN_SEARCH_COMPLETION_KEY_LEN 3
#define GEDIT_VIEW_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), GEDIT_TYPE_VIEW, GeditViewPrivate))
@@ -72,40 +69,12 @@ enum
struct _GeditViewPrivate
{
GSettings *editor_settings;
-
- SearchMode search_mode;
-
- GtkTextIter start_search_iter;
-
- /* used to restore the search state if an
- * incremental search is cancelled
- */
- gchar *old_search_text;
- guint old_search_flags;
-
- /* used to remeber the state of the last
- * incremental search (the document search
- * state may be changed by the search dialog)
- */
- guint search_flags;
- gboolean wrap_around;
-
- GtkWidget *search_window;
- GtkWidget *search_entry;
-
- guint typeselect_flush_timeout;
- guint search_entry_changed_id;
-
- gboolean disable_popdown;
GtkTextBuffer *current_buffer;
PeasExtensionSet *extensions;
};
-/* The search entry completion is shared among all the views */
-GtkListStore *search_completion_model = NULL;
-
static void gedit_view_destroy (GtkObject *object);
static void gedit_view_finalize (GObject *object);
static gint gedit_view_focus_out (GtkWidget *widget,
@@ -131,13 +100,8 @@ static gboolean gedit_view_button_press_event (GtkWidget *widget,
GdkEventButton *event);
static void gedit_view_realize (GtkWidget *widget);
-static gboolean start_interactive_search (GeditView *view);
-static gboolean start_interactive_goto_line (GeditView *view);
static gboolean reset_searched_text (GeditView *view);
-static void hide_search_window (GeditView *view,
- gboolean cancel);
-
static gint gedit_view_expose (GtkWidget *widget,
GdkEventExpose *event);
@@ -164,12 +128,6 @@ enum
static guint view_signals [LAST_SIGNAL] = { 0 };
-typedef enum
-{
- GEDIT_SEARCH_ENTRY_NORMAL,
- GEDIT_SEARCH_ENTRY_NOT_FOUND
-} GeditSearchEntryBgColor;
-
static void
document_read_only_notify_handler (GeditDocument *document,
GParamSpec *pspec,
@@ -216,38 +174,36 @@ gedit_view_class_init (GeditViewClass *klass)
widget_class->drag_drop = gedit_view_drag_drop;
widget_class->button_press_event = gedit_view_button_press_event;
widget_class->realize = gedit_view_realize;
- klass->start_interactive_search = start_interactive_search;
- klass->start_interactive_goto_line = start_interactive_goto_line;
- klass->reset_searched_text = reset_searched_text;
+ klass->reset_searched_text = reset_searched_text;
text_view_class->delete_from_cursor = gedit_view_delete_from_cursor;
-
+
view_signals[START_INTERACTIVE_SEARCH] =
- g_signal_new ("start_interactive_search",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
- G_STRUCT_OFFSET (GeditViewClass, start_interactive_search),
- NULL, NULL,
- gedit_marshal_BOOLEAN__NONE,
- G_TYPE_BOOLEAN, 0);
+ g_signal_new ("start-interactive-search",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (GeditViewClass, start_interactive_search),
+ NULL, NULL,
+ gedit_marshal_BOOLEAN__NONE,
+ G_TYPE_BOOLEAN, 0);
view_signals[START_INTERACTIVE_GOTO_LINE] =
- g_signal_new ("start_interactive_goto_line",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
- G_STRUCT_OFFSET (GeditViewClass, start_interactive_goto_line),
- NULL, NULL,
- gedit_marshal_BOOLEAN__NONE,
- G_TYPE_BOOLEAN, 0);
+ g_signal_new ("start-interactive-goto-line",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (GeditViewClass, start_interactive_goto_line),
+ NULL, NULL,
+ gedit_marshal_BOOLEAN__NONE,
+ G_TYPE_BOOLEAN, 0);
view_signals[RESET_SEARCHED_TEXT] =
- g_signal_new ("reset_searched_text",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
- G_STRUCT_OFFSET (GeditViewClass, reset_searched_text),
+ g_signal_new ("reset-searched-text",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (GeditViewClass, reset_searched_text),
NULL, NULL,
gedit_marshal_BOOLEAN__NONE,
- G_TYPE_BOOLEAN, 0);
+ G_TYPE_BOOLEAN, 0);
/* A new signal DROP_URIS has been added to allow plugins to intercept
* the default dnd behaviour of 'text/uri-list'. GeditView now handles
@@ -270,17 +226,17 @@ gedit_view_class_init (GeditViewClass *klass)
g_type_class_add_private (klass, sizeof (GeditViewPrivate));
binding_set = gtk_binding_set_by_class (klass);
-
+
gtk_binding_entry_add_signal (binding_set,
- GDK_k,
- GDK_CONTROL_MASK,
- "start_interactive_search", 0);
-
+ GDK_k,
+ GDK_CONTROL_MASK,
+ "start-interactive-search", 0);
+
gtk_binding_entry_add_signal (binding_set,
- GDK_i,
- GDK_CONTROL_MASK,
- "start_interactive_goto_line", 0);
-
+ GDK_i,
+ GDK_CONTROL_MASK,
+ "start-interactive-goto-line", 0);
+
gtk_binding_entry_add_signal (binding_set,
GDK_k,
GDK_CONTROL_MASK | GDK_SHIFT_MASK,
@@ -438,9 +394,6 @@ gedit_view_init (GeditView *view)
"indent_on_tab", TRUE,
NULL);
- view->priv->typeselect_flush_timeout = 0;
- view->priv->wrap_around = TRUE;
-
/* Drag and drop support */
tl = gtk_drag_dest_get_target_list (GTK_WIDGET (view));
@@ -481,19 +434,6 @@ gedit_view_destroy (GtkObject *object)
view->priv->extensions = NULL;
}
- if (view->priv->search_window != NULL)
- {
- gtk_widget_destroy (view->priv->search_window);
- view->priv->search_window = NULL;
- view->priv->search_entry = NULL;
-
- if (view->priv->typeselect_flush_timeout != 0)
- {
- g_source_remove (view->priv->typeselect_flush_timeout);
- view->priv->typeselect_flush_timeout = 0;
- }
- }
-
/* Disconnect notify buffer because the destroy of the textview will
set the buffer to NULL, and we call get_buffer in the notify which
would reinstate a GtkTextBuffer which we don't want */
@@ -505,7 +445,7 @@ gedit_view_destroy (GtkObject *object)
g_object_unref (view->priv->editor_settings);
view->priv->editor_settings = NULL;
}
-
+
(* GTK_OBJECT_CLASS (gedit_view_parent_class)->destroy) (object);
}
@@ -518,24 +458,16 @@ gedit_view_finalize (GObject *object)
current_buffer_removed (view);
- g_free (view->priv->old_search_text);
-
(* G_OBJECT_CLASS (gedit_view_parent_class)->finalize) (object);
}
static gint
gedit_view_focus_out (GtkWidget *widget, GdkEventFocus *event)
{
- GeditView *view = GEDIT_VIEW (widget);
-
gtk_widget_queue_draw (widget);
-
- /* hide interactive search dialog */
- if (view->priv->search_window != NULL)
- hide_search_window (view, FALSE);
-
+
(* GTK_WIDGET_CLASS (gedit_view_parent_class)->focus_out_event) (widget, event);
-
+
return FALSE;
}
@@ -776,1163 +708,6 @@ gedit_view_set_font (GeditView *view,
pango_font_description_free (font_desc);
}
-static void
-add_search_completion_entry (const gchar *str)
-{
- gchar *text;
- gboolean valid;
- GtkTreeModel *model;
- GtkTreeIter iter;
-
- if (str == NULL)
- return;
-
- text = gedit_utils_unescape_search_text (str);
-
- if (g_utf8_strlen (text, -1) < MIN_SEARCH_COMPLETION_KEY_LEN)
- {
- g_free (text);
- return;
- }
-
- g_return_if_fail (GTK_IS_TREE_MODEL (search_completion_model));
-
- model = GTK_TREE_MODEL (search_completion_model);
-
- /* Get the first iter in the list */
- valid = gtk_tree_model_get_iter_first (model, &iter);
-
- while (valid)
- {
- /* Walk through the list, reading each row */
- gchar *str_data;
-
- gtk_tree_model_get (model,
- &iter,
- 0,
- &str_data,
- -1);
-
- if (strcmp (text, str_data) == 0)
- {
- g_free (text);
- g_free (str_data);
- gtk_list_store_move_after (GTK_LIST_STORE (model),
- &iter,
- NULL);
-
- return;
- }
-
- g_free (str_data);
-
- valid = gtk_tree_model_iter_next (model, &iter);
- }
-
- gtk_list_store_prepend (GTK_LIST_STORE (model), &iter);
- gtk_list_store_set (GTK_LIST_STORE (model),
- &iter,
- 0,
- text,
- -1);
-
- g_free (text);
-}
-
-static void
-set_entry_background (GtkWidget *entry,
- GeditSearchEntryBgColor col)
-{
- if (col == GEDIT_SEARCH_ENTRY_NOT_FOUND)
- {
- GdkColor red;
- GdkColor white;
-
- /* FIXME: a11y and theme */
-
- gdk_color_parse ("#FF6666", &red);
- gdk_color_parse ("white", &white);
-
- gtk_widget_modify_base (entry,
- GTK_STATE_NORMAL,
- &red);
- gtk_widget_modify_text (entry,
- GTK_STATE_NORMAL,
- &white);
- }
- else /* reset */
- {
- gtk_widget_modify_base (entry,
- GTK_STATE_NORMAL,
- NULL);
- gtk_widget_modify_text (entry,
- GTK_STATE_NORMAL,
- NULL);
- }
-}
-
-static gboolean
-run_search (GeditView *view,
- const gchar *entry_text,
- gboolean search_backward,
- gboolean wrap_around,
- gboolean typing)
-{
- GtkTextIter start_iter;
- GtkTextIter match_start;
- GtkTextIter match_end;
- gboolean found = FALSE;
- GeditDocument *doc;
-
- g_return_val_if_fail (view->priv->search_mode == SEARCH, FALSE);
-
- doc = GEDIT_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
-
- start_iter = view->priv->start_search_iter;
-
- if (*entry_text != '\0')
- {
- if (!search_backward)
- {
- if (!typing)
- {
- /* forward and _NOT_ typing */
- gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (doc),
- &start_iter,
- &match_end);
-
- gtk_text_iter_order (&match_end, &start_iter);
- }
-
- /* run search */
- found = gedit_document_search_forward (doc,
- &start_iter,
- NULL,
- &match_start,
- &match_end);
- }
- else if (!typing)
- {
- /* backward and not typing */
- gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (doc),
- &start_iter,
- &match_end);
-
- /* run search */
- found = gedit_document_search_backward (doc,
- NULL,
- &start_iter,
- &match_start,
- &match_end);
- }
- else
- {
- /* backward (while typing) */
- g_return_val_if_reached (FALSE);
-
- }
-
- if (!found && wrap_around)
- {
- if (!search_backward)
- {
- found = gedit_document_search_forward (doc,
- NULL,
- NULL, /* FIXME: set the end_inter */
- &match_start,
- &match_end);
- }
- else
- {
- found = gedit_document_search_backward (doc,
- NULL, /* FIXME: set the start_inter */
- NULL,
- &match_start,
- &match_end);
- }
- }
- }
- else
- {
- gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (doc),
- &start_iter,
- NULL);
- }
-
- if (found)
- {
- gtk_text_buffer_place_cursor (GTK_TEXT_BUFFER (doc),
- &match_start);
-
- gtk_text_buffer_move_mark_by_name (GTK_TEXT_BUFFER (doc),
- "selection_bound", &match_end);
- }
- else if (typing)
- {
- gtk_text_buffer_place_cursor (GTK_TEXT_BUFFER (doc),
- &view->priv->start_search_iter);
- }
-
- if (found || (*entry_text == '\0'))
- {
- gedit_view_scroll_to_cursor (view);
-
- set_entry_background (view->priv->search_entry,
- GEDIT_SEARCH_ENTRY_NORMAL);
- }
- else
- {
- set_entry_background (view->priv->search_entry,
- GEDIT_SEARCH_ENTRY_NOT_FOUND);
- }
-
- return found;
-}
-
-/* Cut and paste from gtkwindow.c */
-static void
-send_focus_change (GtkWidget *widget,
- gboolean in)
-{
- GdkEvent *fevent = gdk_event_new (GDK_FOCUS_CHANGE);
-
- g_object_ref (widget);
-
- fevent->focus_change.type = GDK_FOCUS_CHANGE;
- fevent->focus_change.window = g_object_ref (gtk_widget_get_window (widget));
- fevent->focus_change.in = in;
-
- gtk_widget_send_focus_change (widget, fevent);
-
- gdk_event_free (fevent);
-}
-
-static void
-hide_search_window (GeditView *view, gboolean cancel)
-{
- if (view->priv->disable_popdown)
- return;
-
- if (view->priv->search_entry_changed_id != 0)
- {
- g_signal_handler_disconnect (view->priv->search_entry,
- view->priv->search_entry_changed_id);
- view->priv->search_entry_changed_id = 0;
- }
-
- if (view->priv->typeselect_flush_timeout != 0)
- {
- g_source_remove (view->priv->typeselect_flush_timeout);
- view->priv->typeselect_flush_timeout = 0;
- }
-
- /* send focus-in event */
- send_focus_change (GTK_WIDGET (view->priv->search_entry), FALSE);
- gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view), TRUE);
- gtk_widget_hide (view->priv->search_window);
-
- if (cancel)
- {
- GtkTextBuffer *buffer;
-
- buffer = GTK_TEXT_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
- gtk_text_buffer_place_cursor (buffer, &view->priv->start_search_iter);
-
- gedit_view_scroll_to_cursor (view);
- }
-
- /* make sure a focus event is sent for the edit area */
- send_focus_change (GTK_WIDGET (view), TRUE);
-}
-
-static gboolean
-search_entry_flush_timeout (GeditView *view)
-{
- GDK_THREADS_ENTER ();
-
- view->priv->typeselect_flush_timeout = 0;
- hide_search_window (view, FALSE);
-
- GDK_THREADS_LEAVE ();
-
- return FALSE;
-}
-
-static void
-update_search_window_position (GeditView *view)
-{
- gint x, y;
- gint view_x, view_y;
- GdkWindow *view_window = gtk_widget_get_window (GTK_WIDGET (view));
-
- gtk_widget_realize (view->priv->search_window);
-
- gdk_window_get_origin (view_window, &view_x, &view_y);
-
- x = MAX (12, view_x + 12);
- y = MAX (12, view_y - 12);
-
- gtk_window_move (GTK_WINDOW (view->priv->search_window), x, y);
-}
-
-static gboolean
-search_window_delete_event (GtkWidget *widget,
- GdkEventAny *event,
- GeditView *view)
-{
- hide_search_window (view, FALSE);
-
- return TRUE;
-}
-
-static gboolean
-search_window_button_press_event (GtkWidget *widget,
- GdkEventButton *event,
- GeditView *view)
-{
- hide_search_window (view, FALSE);
-
- gtk_propagate_event (GTK_WIDGET (view), (GdkEvent *)event);
-
- return FALSE;
-}
-
-static void
-search_again (GeditView *view,
- gboolean search_backward)
-{
- const gchar *entry_text;
-
- g_return_if_fail (view->priv->search_mode == SEARCH);
-
- /* SEARCH mode */
- /* renew the flush timeout */
- if (view->priv->typeselect_flush_timeout != 0)
- {
- g_source_remove (view->priv->typeselect_flush_timeout);
- view->priv->typeselect_flush_timeout =
- g_timeout_add (GEDIT_VIEW_SEARCH_DIALOG_TIMEOUT,
- (GSourceFunc)search_entry_flush_timeout,
- view);
- }
-
- entry_text = gtk_entry_get_text (GTK_ENTRY (view->priv->search_entry));
-
- add_search_completion_entry (entry_text);
-
- run_search (view,
- entry_text,
- search_backward,
- view->priv->wrap_around,
- FALSE);
-}
-
-static gboolean
-search_window_scroll_event (GtkWidget *widget,
- GdkEventScroll *event,
- GeditView *view)
-{
- gboolean retval = FALSE;
-
- if (view->priv->search_mode == GOTO_LINE)
- return retval;
-
- /* SEARCH mode */
- if (event->direction == GDK_SCROLL_UP)
- {
- search_again (view, TRUE);
- retval = TRUE;
- }
- else if (event->direction == GDK_SCROLL_DOWN)
- {
- search_again (view, FALSE);
- retval = TRUE;
- }
-
- return retval;
-}
-
-static gboolean
-search_window_key_press_event (GtkWidget *widget,
- GdkEventKey *event,
- GeditView *view)
-{
- gboolean retval = FALSE;
- guint modifiers;
-
- modifiers = gtk_accelerator_get_default_mod_mask ();
-
- /* Close window */
- if (event->keyval == GDK_Tab)
- {
- hide_search_window (view, FALSE);
- retval = TRUE;
- }
-
- /* Close window and cancel the search */
- if (event->keyval == GDK_Escape)
- {
- if (view->priv->search_mode == SEARCH)
- {
- GeditDocument *doc;
-
- /* restore document search so that Find Next does the right thing */
- doc = GEDIT_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
- gedit_document_set_search_text (doc,
- view->priv->old_search_text,
- view->priv->old_search_flags);
-
- }
-
- hide_search_window (view, TRUE);
- retval = TRUE;
- }
-
- if (view->priv->search_mode == GOTO_LINE)
- return retval;
-
- /* SEARCH mode */
-
- /* select previous matching iter */
- if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up)
- {
- search_again (view, TRUE);
- retval = TRUE;
- }
-
- if (((event->state & modifiers) == (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) &&
- (event->keyval == GDK_g || event->keyval == GDK_G))
- {
- search_again (view, TRUE);
- retval = TRUE;
- }
-
- /* select next matching iter */
- if (event->keyval == GDK_Down || event->keyval == GDK_KP_Down)
- {
- search_again (view, FALSE);
- retval = TRUE;
- }
-
- if (((event->state & modifiers) == GDK_CONTROL_MASK) &&
- (event->keyval == GDK_g || event->keyval == GDK_G))
- {
- search_again (view, FALSE);
- retval = TRUE;
- }
-
- return retval;
-}
-
-static void
-search_entry_activate (GtkEntry *entry,
- GeditView *view)
-{
- hide_search_window (view, FALSE);
-}
-
-static void
-wrap_around_menu_item_toggled (GtkCheckMenuItem *checkmenuitem,
- GeditView *view)
-{
- view->priv->wrap_around = gtk_check_menu_item_get_active (checkmenuitem);
-}
-
-static void
-match_entire_word_menu_item_toggled (GtkCheckMenuItem *checkmenuitem,
- GeditView *view)
-{
- GEDIT_SEARCH_SET_ENTIRE_WORD (view->priv->search_flags,
- gtk_check_menu_item_get_active (checkmenuitem));
-}
-
-static void
-match_case_menu_item_toggled (GtkCheckMenuItem *checkmenuitem,
- GeditView *view)
-{
- GEDIT_SEARCH_SET_CASE_SENSITIVE (view->priv->search_flags,
- gtk_check_menu_item_get_active (checkmenuitem));
-}
-
-static gboolean
-real_search_enable_popdown (gpointer data)
-{
- GeditView *view = (GeditView *)data;
-
- GDK_THREADS_ENTER ();
-
- view->priv->disable_popdown = FALSE;
-
- GDK_THREADS_LEAVE ();
-
- return FALSE;
-}
-
-static void
-search_enable_popdown (GtkWidget *widget,
- GeditView *view)
-{
- g_timeout_add (200, real_search_enable_popdown, view);
-
- /* renew the flush timeout */
- if (view->priv->typeselect_flush_timeout != 0)
- g_source_remove (view->priv->typeselect_flush_timeout);
-
- view->priv->typeselect_flush_timeout =
- g_timeout_add (GEDIT_VIEW_SEARCH_DIALOG_TIMEOUT,
- (GSourceFunc)search_entry_flush_timeout,
- view);
-}
-
-static void
-add_popup_menu_items (GtkWidget *menu,
- GeditView *view)
-{
- GtkWidget *menu_item;
-
- /* create "Wrap Around" menu item. */
- menu_item = gtk_check_menu_item_new_with_mnemonic (_("_Wrap Around"));
- g_signal_connect (G_OBJECT (menu_item), "toggled",
- G_CALLBACK (wrap_around_menu_item_toggled),
- view);
- gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
- gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item),
- view->priv->wrap_around);
- gtk_widget_show (menu_item);
-
- /* create "Match Entire Word Only" menu item. */
- menu_item = gtk_check_menu_item_new_with_mnemonic (_("Match _Entire Word Only"));
- g_signal_connect (G_OBJECT (menu_item), "toggled",
- G_CALLBACK (match_entire_word_menu_item_toggled),
- view);
- gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
- gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item),
- GEDIT_SEARCH_IS_ENTIRE_WORD (view->priv->search_flags));
- gtk_widget_show (menu_item);
-
- /* create "Match Case" menu item. */
- menu_item = gtk_check_menu_item_new_with_mnemonic (_("_Match Case"));
- g_signal_connect (G_OBJECT (menu_item), "toggled",
- G_CALLBACK (match_case_menu_item_toggled),
- view);
- gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
- gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item),
- GEDIT_SEARCH_IS_CASE_SENSITIVE (view->priv->search_flags));
- gtk_widget_show (menu_item);
-}
-
-static void
-search_entry_populate_popup (GtkEntry *entry,
- GtkMenu *menu,
- GeditView *view)
-{
- GtkWidget *menu_item;
-
- view->priv->disable_popdown = TRUE;
- g_signal_connect (menu, "hide",
- G_CALLBACK (search_enable_popdown), view);
-
- if (view->priv->search_mode == GOTO_LINE)
- return;
-
- /* separator */
- menu_item = gtk_menu_item_new ();
- gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
- gtk_widget_show (menu_item);
-
- add_popup_menu_items (GTK_WIDGET (menu), view);
-}
-
-static void
-search_entry_icon_release (GtkEntry *entry,
- GtkEntryIconPosition icon_pos,
- GdkEventButton *event,
- GeditView *view)
-{
- GtkWidget *menu;
-
- if (view->priv->search_mode == GOTO_LINE ||
- icon_pos != GTK_ENTRY_ICON_PRIMARY)
- return;
-
- menu = gtk_menu_new ();
- gtk_widget_show (menu);
-
- view->priv->disable_popdown = TRUE;
- g_signal_connect (menu, "hide",
- G_CALLBACK (search_enable_popdown), view);
-
- add_popup_menu_items (menu, view);
-
- gtk_menu_popup (GTK_MENU (menu),
- NULL, NULL,
- NULL, NULL,
- event->button, event->time);
-}
-
-static void
-search_entry_insert_text (GtkEditable *editable,
- const gchar *text,
- gint length,
- gint *position,
- GeditView *view)
-{
- if (view->priv->search_mode == GOTO_LINE)
- {
- gunichar c;
- const gchar *p;
- const gchar *end;
- const gchar *next;
-
- p = text;
- end = text + length;
-
- if (p == end)
- return;
-
- c = g_utf8_get_char (p);
-
- if (((c == '-' || c == '+') && *position == 0) ||
- (c == ':' && *position != 0))
- {
- gchar *s = NULL;
-
- if (c == ':')
- {
- s = gtk_editable_get_chars (editable, 0, -1);
- s = g_utf8_strchr (s, -1, ':');
- }
-
- if (s == NULL || s == p)
- {
- next = g_utf8_next_char (p);
- p = next;
- }
-
- g_free (s);
- }
-
- while (p != end)
- {
- next = g_utf8_next_char (p);
-
- c = g_utf8_get_char (p);
-
- if (!g_unichar_isdigit (c))
- {
- g_signal_stop_emission_by_name (editable, "insert_text");
- gtk_widget_error_bell (view->priv->search_entry);
- break;
- }
-
- p = next;
- }
- }
- else
- {
- /* SEARCH mode */
- static gboolean insert_text = FALSE;
- gchar *escaped_text;
- gint new_len;
-
- gedit_debug_message (DEBUG_SEARCH, "Text: %s", text);
-
- /* To avoid recursive behavior */
- if (insert_text)
- return;
-
- escaped_text = gedit_utils_escape_search_text (text);
-
- gedit_debug_message (DEBUG_SEARCH, "Escaped Text: %s", escaped_text);
-
- new_len = strlen (escaped_text);
-
- if (new_len == length)
- {
- g_free (escaped_text);
- return;
- }
-
- insert_text = TRUE;
-
- g_signal_stop_emission_by_name (editable, "insert_text");
-
- gtk_editable_insert_text (editable, escaped_text, new_len, position);
-
- insert_text = FALSE;
-
- g_free (escaped_text);
- }
-}
-
-static void
-customize_for_search_mode (GeditView *view)
-{
- if (view->priv->search_mode == SEARCH)
- {
- gtk_entry_set_icon_from_stock (GTK_ENTRY (view->priv->search_entry),
- GTK_ENTRY_ICON_PRIMARY,
- GTK_STOCK_FIND);
-
- gtk_widget_set_tooltip_text (view->priv->search_entry,
- _("String you want to search for"));
- }
- else
- {
- gtk_entry_set_icon_from_stock (GTK_ENTRY (view->priv->search_entry),
- GTK_ENTRY_ICON_PRIMARY,
- GTK_STOCK_JUMP_TO);
-
- gtk_widget_set_tooltip_text (view->priv->search_entry,
- _("Line you want to move the cursor to"));
- }
-}
-
-static gboolean
-completion_func (GtkEntryCompletion *completion,
- const char *key,
- GtkTreeIter *iter,
- gpointer data)
-{
- gchar *item = NULL;
- gboolean ret = FALSE;
- GtkTreeModel *model;
- GeditViewPrivate *priv = (GeditViewPrivate *)data;
- const gchar *real_key;
-
- if (priv->search_mode == GOTO_LINE)
- return FALSE;
-
- real_key = gtk_entry_get_text (GTK_ENTRY (gtk_entry_completion_get_entry (completion)));
-
- if (g_utf8_strlen (real_key, -1) <= MIN_SEARCH_COMPLETION_KEY_LEN)
- return FALSE;
-
- model = gtk_entry_completion_get_model (completion);
- g_return_val_if_fail (gtk_tree_model_get_column_type (model, 0) == G_TYPE_STRING,
- FALSE);
-
- gtk_tree_model_get (model,
- iter,
- 0,
- &item,
- -1);
-
- if (item == NULL)
- return FALSE;
-
- if (GEDIT_SEARCH_IS_CASE_SENSITIVE (priv->search_flags))
- {
- if (!strncmp (real_key, item, strlen (real_key)))
- ret = TRUE;
- }
- else
- {
- gchar *normalized_string;
- gchar *case_normalized_string;
-
- normalized_string = g_utf8_normalize (item, -1, G_NORMALIZE_ALL);
- case_normalized_string = g_utf8_casefold (normalized_string, -1);
-
- if (!strncmp (key, case_normalized_string, strlen (key)))
- ret = TRUE;
-
- g_free (normalized_string);
- g_free (case_normalized_string);
-
- }
-
- g_free (item);
-
- return ret;
-}
-
-static void
-ensure_search_window (GeditView *view)
-{
- GtkWidget *frame;
- GtkWidget *vbox;
- GtkWidget *toplevel;
- GtkEntryCompletion *completion;
-
- toplevel = gtk_widget_get_toplevel (GTK_WIDGET (view));
-
- if (view->priv->search_window != NULL)
- {
- if (gtk_window_has_group (GTK_WINDOW (toplevel)))
- {
- gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
- GTK_WINDOW (view->priv->search_window));
- }
- else if (gtk_window_has_group (GTK_WINDOW (view->priv->search_window)))
- {
- gtk_window_group_remove_window (gtk_window_get_group (GTK_WINDOW (view->priv->search_window)),
- GTK_WINDOW (view->priv->search_window));
- }
-
- customize_for_search_mode (view);
-
- return;
- }
-
- view->priv->search_window = gtk_window_new (GTK_WINDOW_POPUP);
-
- if (gtk_window_has_group (GTK_WINDOW (toplevel)))
- {
- gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
- GTK_WINDOW (view->priv->search_window));
- }
-
- gtk_window_set_modal (GTK_WINDOW (view->priv->search_window), TRUE);
-
- g_signal_connect (view->priv->search_window, "delete_event",
- G_CALLBACK (search_window_delete_event),
- view);
- g_signal_connect (view->priv->search_window, "key_press_event",
- G_CALLBACK (search_window_key_press_event),
- view);
- g_signal_connect (view->priv->search_window, "button_press_event",
- G_CALLBACK (search_window_button_press_event),
- view);
- g_signal_connect (view->priv->search_window, "scroll_event",
- G_CALLBACK (search_window_scroll_event),
- view);
-
- frame = gtk_frame_new (NULL);
- gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
- gtk_widget_show (frame);
- gtk_container_add (GTK_CONTAINER (view->priv->search_window), frame);
-
- vbox = gtk_vbox_new (FALSE, 0);
- gtk_widget_show (vbox);
- gtk_container_add (GTK_CONTAINER (frame), vbox);
- gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
-
- /* add entry */
- view->priv->search_entry = gtk_entry_new ();
- gtk_widget_show (view->priv->search_entry);
-
- g_signal_connect (view->priv->search_entry, "populate-popup",
- G_CALLBACK (search_entry_populate_popup),
- view);
- g_signal_connect (view->priv->search_entry, "icon-release",
- G_CALLBACK (search_entry_icon_release),
- view);
- g_signal_connect (view->priv->search_entry, "activate",
- G_CALLBACK (search_entry_activate),
- view);
- /* CHECK: do we really need to connect to preedit too? -- Paolo
- g_signal_connect (GTK_ENTRY (view->priv->search_entry)->im_context, "preedit-changed",
- G_CALLBACK (gtk_view_search_preedit_changed),
- view);
- */
- g_signal_connect (view->priv->search_entry,
- "insert_text",
- G_CALLBACK (search_entry_insert_text),
- view);
-
- gtk_container_add (GTK_CONTAINER (vbox),
- view->priv->search_entry);
-
- if (search_completion_model == NULL)
- {
- /* Create a tree model and use it as the completion model */
- search_completion_model = gtk_list_store_new (1, G_TYPE_STRING);
- }
-
- /* Create the completion object for the search entry */
- completion = gtk_entry_completion_new ();
- gtk_entry_completion_set_model (completion,
- GTK_TREE_MODEL (search_completion_model));
-
- /* Use model column 0 as the text column */
- gtk_entry_completion_set_text_column (completion, 0);
-
- gtk_entry_completion_set_minimum_key_length (completion,
- MIN_SEARCH_COMPLETION_KEY_LEN);
-
- gtk_entry_completion_set_popup_completion (completion, FALSE);
- gtk_entry_completion_set_inline_completion (completion, TRUE);
-
- gtk_entry_completion_set_match_func (completion,
- completion_func,
- view->priv,
- NULL);
-
- /* Assign the completion to the entry */
- gtk_entry_set_completion (GTK_ENTRY (view->priv->search_entry),
- completion);
- g_object_unref (completion);
-
- gtk_widget_realize (view->priv->search_entry);
-
- customize_for_search_mode (view);
-}
-
-static gboolean
-get_selected_text (GtkTextBuffer *doc, gchar **selected_text, gint *len)
-{
- GtkTextIter start, end;
-
- g_return_val_if_fail (selected_text != NULL, FALSE);
- g_return_val_if_fail (*selected_text == NULL, FALSE);
-
- if (!gtk_text_buffer_get_selection_bounds (doc, &start, &end))
- {
- if (len != NULL)
- len = 0;
-
- return FALSE;
- }
-
- *selected_text = gtk_text_buffer_get_slice (doc, &start, &end, TRUE);
-
- if (len != NULL)
- *len = g_utf8_strlen (*selected_text, -1);
-
- return TRUE;
-}
-
-static void
-init_search_entry (GeditView *view)
-{
- GtkTextBuffer *buffer;
-
- buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
-
- if (view->priv->search_mode == GOTO_LINE)
- {
- gint line;
- gchar *line_str;
-
- line = gtk_text_iter_get_line (&view->priv->start_search_iter);
-
- line_str = g_strdup_printf ("%d", line + 1);
-
- gtk_entry_set_text (GTK_ENTRY (view->priv->search_entry),
- line_str);
-
- g_free (line_str);
-
- return;
- }
- else
- {
- /* SEARCH mode */
- gboolean selection_exists;
- gchar *find_text = NULL;
- gchar *old_find_text;
- guint old_find_flags = 0;
- gint sel_len = 0;
-
- g_free (view->priv->old_search_text);
-
- old_find_text = gedit_document_get_search_text (GEDIT_DOCUMENT (buffer),
- &old_find_flags);
- if (old_find_text != NULL)
- {
- view->priv->old_search_text = old_find_text;
- add_search_completion_entry (old_find_text);
- }
-
- if (old_find_flags != 0)
- {
- view->priv->old_search_flags = old_find_flags;
- }
-
- selection_exists = get_selected_text (buffer,
- &find_text,
- &sel_len);
-
- if (selection_exists && (find_text != NULL) && (sel_len <= 160))
- {
- gtk_entry_set_text (GTK_ENTRY (view->priv->search_entry),
- find_text);
- }
- else
- {
- gtk_entry_set_text (GTK_ENTRY (view->priv->search_entry),
- "");
- }
-
- g_free (find_text);
- }
-}
-
-static void
-search_init (GtkWidget *entry,
- GeditView *view)
-{
- GeditDocument *doc;
- const gchar *entry_text;
-
- /* renew the flush timeout */
- if (view->priv->typeselect_flush_timeout != 0)
- {
- g_source_remove (view->priv->typeselect_flush_timeout);
- view->priv->typeselect_flush_timeout =
- g_timeout_add (GEDIT_VIEW_SEARCH_DIALOG_TIMEOUT,
- (GSourceFunc)search_entry_flush_timeout,
- view);
- }
-
- doc = GEDIT_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
-
- entry_text = gtk_entry_get_text (GTK_ENTRY (entry));
-
- if (view->priv->search_mode == SEARCH)
- {
- gchar *search_text;
- guint search_flags;
-
- search_text = gedit_document_get_search_text (doc, &search_flags);
-
- if ((search_text == NULL) ||
- (strcmp (search_text, entry_text) != 0) ||
- search_flags != view->priv->search_flags)
- {
- gedit_document_set_search_text (doc,
- entry_text,
- view->priv->search_flags);
- }
-
- g_free (search_text);
-
- run_search (view,
- entry_text,
- FALSE,
- view->priv->wrap_around,
- TRUE);
- }
- else
- {
- if (*entry_text != '\0')
- {
- gboolean moved, moved_offset;
- gint line;
- gint offset_line = 0;
- gint line_offset = 0;
- gchar **split_text = NULL;
- const gchar *text;
-
- split_text = g_strsplit (entry_text, ":", -1);
-
- if (g_strv_length (split_text) > 1)
- {
- text = split_text[0];
- }
- else
- {
- text = entry_text;
- }
-
- if (*text == '-')
- {
- gint cur_line = gtk_text_iter_get_line (&view->priv->start_search_iter);
-
- if (*(text + 1) != '\0')
- offset_line = MAX (atoi (text + 1), 0);
-
- line = MAX (cur_line - offset_line, 0);
- }
- else if (*entry_text == '+')
- {
- gint cur_line = gtk_text_iter_get_line (&view->priv->start_search_iter);
-
- if (*(text + 1) != '\0')
- offset_line = MAX (atoi (text + 1), 0);
-
- line = cur_line + offset_line;
- }
- else
- {
- line = MAX (atoi (text) - 1, 0);
- }
-
- if (split_text[1] != NULL)
- {
- line_offset = atoi (split_text[1]);
- }
-
- g_strfreev (split_text);
-
- moved = gedit_document_goto_line (doc, line);
- moved_offset = gedit_document_goto_line_offset (doc, line,
- line_offset);
-
- gedit_view_scroll_to_cursor (view);
-
- if (!moved || !moved_offset)
- {
- set_entry_background (view->priv->search_entry,
- GEDIT_SEARCH_ENTRY_NOT_FOUND);
- }
- else
- {
- set_entry_background (view->priv->search_entry,
- GEDIT_SEARCH_ENTRY_NORMAL);
- }
- }
- }
-}
-
-static gboolean
-start_interactive_search_real (GeditView *view)
-{
- GtkTextBuffer *buffer;
-
- if ((view->priv->search_window != NULL) &&
- gtk_widget_get_visible (view->priv->search_window))
- {
- return TRUE;
- }
-
- if (!gtk_widget_has_focus (GTK_WIDGET (view)))
- return FALSE;
-
- buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
-
- if (view->priv->search_mode == SEARCH)
- {
- gtk_text_buffer_get_selection_bounds (buffer, &view->priv->start_search_iter, NULL);
- }
- else
- {
- gtk_text_buffer_get_iter_at_mark (buffer,
- &view->priv->start_search_iter,
- gtk_text_buffer_get_insert (buffer));
- }
-
- ensure_search_window (view);
-
- /* done, show it */
- update_search_window_position (view);
- gtk_widget_show (view->priv->search_window);
-
- if (view->priv->search_entry_changed_id == 0)
- {
- view->priv->search_entry_changed_id =
- g_signal_connect (view->priv->search_entry,
- "changed",
- G_CALLBACK (search_init),
- view);
- }
-
- init_search_entry (view);
-
- view->priv->typeselect_flush_timeout =
- g_timeout_add (GEDIT_VIEW_SEARCH_DIALOG_TIMEOUT,
- (GSourceFunc) search_entry_flush_timeout,
- view);
-
- gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view), FALSE);
- gtk_widget_grab_focus (view->priv->search_entry);
-
- send_focus_change (view->priv->search_entry, TRUE);
-
- return TRUE;
-}
-
static gboolean
reset_searched_text (GeditView *view)
{
@@ -1945,22 +720,6 @@ reset_searched_text (GeditView *view)
return TRUE;
}
-static gboolean
-start_interactive_search (GeditView *view)
-{
- view->priv->search_mode = SEARCH;
-
- return start_interactive_search_real (view);
-}
-
-static gboolean
-start_interactive_goto_line (GeditView *view)
-{
- view->priv->search_mode = GOTO_LINE;
-
- return start_interactive_search_real (view);
-}
-
static gint
gedit_view_expose (GtkWidget *widget,
GdkEventExpose *event)
diff --git a/gedit/theatrics/Makefile.am b/gedit/theatrics/Makefile.am
new file mode 100644
index 0000000..d79fe42
--- /dev/null
+++ b/gedit/theatrics/Makefile.am
@@ -0,0 +1,52 @@
+INCLUDES = \
+ -I$(top_srcdir) \
+ -I$(top_builddir) \
+ -I$(top_srcdir)/gedit \
+ -I$(top_builddir)/gedit \
+ $(GEDIT_CFLAGS) \
+ $(WARN_CFLAGS) \
+ $(DISABLE_DEPRECATED_CFLAGS)
+
+noinst_LTLIBRARIES = libtheatrics.la
+
+BUILT_SOURCES = \
+ gedit-theatrics-enum-types.h \
+ gedit-theatrics-enum-types.c \
+ gedit-theatrics-marshal.h \
+ gedit-theatrics-marshal.c
+
+libtheatrics_la_SOURCES = \
+ gedit-theatrics-actor.h \
+ gedit-theatrics-actor.c \
+ gedit-theatrics-animated-widget.h \
+ gedit-theatrics-animated-widget.c \
+ gedit-theatrics-choreographer.h \
+ gedit-theatrics-choreographer.c \
+ gedit-theatrics-stage.h \
+ gedit-theatrics-stage.c \
+ gedit-theatrics-utils.h \
+ gedit-theatrics-utils.c \
+ $(BUILT_SOURCES)
+
+ENUM_TYPES = \
+ gedit-theatrics-choreographer.h
+
+gedit-theatrics-enum-types.h: gedit-theatrics-enum-types.h.template $(ENUM_TYPES) $(GLIB_MKENUMS)
+ $(AM_V_GEN) (cd $(srcdir) && $(GLIB_MKENUMS) --template gedit-theatrics-enum-types.h.template $(ENUM_TYPES)) > $@
+
+gedit-theatrics-enum-types.c: gedit-theatrics-enum-types.c.template $(ENUM_TYPES) $(GLIB_MKENUMS)
+ $(AM_V_GEN) (cd $(srcdir) && $(GLIB_MKENUMS) --template gedit-theatrics-enum-types.c.template $(ENUM_TYPES)) > $@
+
+gedit-theatrics-marshal.h: gedit-theatrics-marshal.list $(GLIB_GENMARSHAL)
+ $(AM_V_GEN) $(GLIB_GENMARSHAL) $< --header --prefix=gedit_theatrics_marshal > $@
+
+gedit-theatrics-marshal.c: gedit-theatrics-marshal.list $(GLIB_GENMARSHAL)
+ $(AM_V_GEN) echo "#include \"gedit-theatrics-marshal.h\"" > $@ && \
+ $(GLIB_GENMARSHAL) $< --body --prefix=gedit_theatrics_marshal >> $@
+
+EXTRA_DIST = \
+ gedit-theatrics-marshal.list
+
+CLEANFILES = $(BUILT_SOURCES)
+
+-include $(top_srcdir)/git.mk
diff --git a/gedit/theatrics/gedit-theatrics-actor.c b/gedit/theatrics/gedit-theatrics-actor.c
new file mode 100644
index 0000000..772acaa
--- /dev/null
+++ b/gedit/theatrics/gedit-theatrics-actor.c
@@ -0,0 +1,279 @@
+/*
+ * gedit-theatrics-actor.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 2010 - Ignacio Casal Quinteiro
+ *
+ * Based on Aaron Bockover <abockover novell com> work.
+ *
+ * gedit is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * gedit 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 gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#include "gedit-theatrics-actor.h"
+
+
+#define GEDIT_THEATRICS_ACTOR_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GEDIT_TYPE_THEATRICS_ACTOR, GeditTheatricsActorPrivate))
+
+struct _GeditTheatricsActorPrivate
+{
+ GObject *target;
+
+ guint duration;
+ gdouble frames;
+ gdouble percent;
+
+ GTimeVal start_time;
+
+ guint can_expire : 1;
+};
+
+enum
+{
+ PROP_0,
+ PROP_TARGET,
+ PROP_DURATION
+};
+
+G_DEFINE_TYPE (GeditTheatricsActor, gedit_theatrics_actor, G_TYPE_OBJECT)
+
+static void
+gedit_theatrics_actor_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (gedit_theatrics_actor_parent_class)->finalize (object);
+}
+
+static void
+gedit_theatrics_actor_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GeditTheatricsActor *actor = GEDIT_THEATRICS_ACTOR (object);
+
+ switch (prop_id)
+ {
+ case PROP_TARGET:
+ g_value_set_object (value, actor->priv->target);
+ break;
+ case PROP_DURATION:
+ g_value_set_uint (value, actor->priv->duration);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gedit_theatrics_actor_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GeditTheatricsActor *actor = GEDIT_THEATRICS_ACTOR (object);
+
+ switch (prop_id)
+ {
+ case PROP_TARGET:
+ {
+ GObject *target;
+
+ target = g_value_get_object (value);
+
+ if (target != NULL)
+ {
+ actor->priv->target = target;
+ }
+
+ break;
+ }
+ case PROP_DURATION:
+ actor->priv->duration = g_value_get_uint (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gedit_theatrics_actor_class_init (GeditTheatricsActorClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gedit_theatrics_actor_finalize;
+ object_class->get_property = gedit_theatrics_actor_get_property;
+ object_class->set_property = gedit_theatrics_actor_set_property;
+
+ g_object_class_install_property (object_class, PROP_TARGET,
+ g_param_spec_object ("target",
+ "Target",
+ "The Target",
+ G_TYPE_OBJECT,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (object_class, PROP_DURATION,
+ g_param_spec_uint ("duration",
+ "Duration",
+ "The duration",
+ 0,
+ G_MAXUINT,
+ 0,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+
+ g_type_class_add_private (object_class, sizeof (GeditTheatricsActorPrivate));
+}
+
+static void
+gedit_theatrics_actor_init (GeditTheatricsActor *actor)
+{
+ actor->priv = GEDIT_THEATRICS_ACTOR_GET_PRIVATE (actor);
+
+ actor->priv->can_expire = TRUE;
+
+ gedit_theatrics_actor_reset (actor, actor->priv->duration);
+}
+
+GeditTheatricsActor *
+gedit_theatrics_actor_new (GObject *target,
+ guint duration)
+{
+ return g_object_new (GEDIT_TYPE_THEATRICS_ACTOR,
+ "target", target,
+ "duration", duration,
+ NULL);
+}
+
+/* Use duration = -1 to not set a new duration */
+void
+gedit_theatrics_actor_reset (GeditTheatricsActor *actor,
+ guint duration)
+{
+ g_return_if_fail (GEDIT_IS_THEATRICS_ACTOR (actor));
+
+ g_get_current_time (&actor->priv->start_time);
+ actor->priv->frames = 0.0;
+ actor->priv->percent = 0.0;
+
+ if (duration > -1)
+ {
+ actor->priv->duration = duration;
+ }
+}
+
+void
+gedit_theatrics_actor_step (GeditTheatricsActor *actor)
+{
+ GTimeVal now;
+ gdouble now_num, start_time;
+
+ g_return_if_fail (GEDIT_IS_THEATRICS_ACTOR (actor));
+
+ if (!actor->priv->can_expire && actor->priv->percent >= 1.0)
+ {
+ gedit_theatrics_actor_reset (actor, actor->priv->duration);
+ }
+
+ g_get_current_time (&now);
+
+ now_num = now.tv_sec * 1000 + now.tv_usec / 1000;
+ start_time = actor->priv->start_time.tv_sec * 1000 + actor->priv->start_time.tv_usec / 1000;
+
+ actor->priv->percent = ((now_num - start_time) / actor->priv->duration);
+
+ actor->priv->frames++;
+}
+
+GObject *
+gedit_theatrics_actor_get_target (GeditTheatricsActor *actor)
+{
+ g_return_val_if_fail (GEDIT_IS_THEATRICS_ACTOR (actor), NULL);
+
+ return actor->priv->target;
+}
+
+gboolean
+gedit_theatrics_actor_get_expired (GeditTheatricsActor *actor)
+{
+ g_return_val_if_fail (GEDIT_IS_THEATRICS_ACTOR (actor), FALSE);
+
+ return (actor->priv->can_expire && actor->priv->percent >= 1.0);
+}
+
+gboolean
+gedit_theatrics_actor_get_can_expire (GeditTheatricsActor *actor)
+{
+ g_return_val_if_fail (GEDIT_IS_THEATRICS_ACTOR (actor), FALSE);
+
+ return actor->priv->can_expire;
+}
+
+void
+gedit_theatrics_actor_set_can_expire (GeditTheatricsActor *actor,
+ gboolean can_expire)
+{
+ g_return_if_fail (GEDIT_IS_THEATRICS_ACTOR (actor));
+
+ actor->priv->can_expire = can_expire;
+}
+
+guint
+gedit_theatrics_actor_get_duration (GeditTheatricsActor *actor)
+{
+ g_return_val_if_fail (GEDIT_IS_THEATRICS_ACTOR (actor), 0.0);
+
+ return actor->priv->duration;
+}
+
+GTimeVal
+gedit_theatrics_actor_get_start_time (GeditTheatricsActor *actor)
+{
+ GTimeVal r = {0, };
+
+ g_return_val_if_fail (GEDIT_IS_THEATRICS_ACTOR (actor), r);
+
+ return actor->priv->start_time;
+}
+
+gdouble
+gedit_theatrics_actor_get_frames (GeditTheatricsActor *actor)
+{
+ g_return_val_if_fail (GEDIT_IS_THEATRICS_ACTOR (actor), 0.0);
+
+ return actor->priv->frames;
+}
+
+gdouble
+gedit_theatrics_actor_get_frames_per_second (GeditTheatricsActor *actor)
+{
+ g_return_val_if_fail (GEDIT_IS_THEATRICS_ACTOR (actor), 0.0);
+
+ return (actor->priv->frames / (actor->priv->duration / 1000.0));
+}
+
+gdouble
+gedit_theatrics_actor_get_percent (GeditTheatricsActor *actor)
+{
+ g_return_val_if_fail (GEDIT_IS_THEATRICS_ACTOR (actor), 0.0);
+
+ return MAX (0.0, MIN (1.0, actor->priv->percent));
+}
+
+/* ex:ts=8:noet: */
diff --git a/gedit/theatrics/gedit-theatrics-actor.h b/gedit/theatrics/gedit-theatrics-actor.h
new file mode 100644
index 0000000..8f81fcb
--- /dev/null
+++ b/gedit/theatrics/gedit-theatrics-actor.h
@@ -0,0 +1,90 @@
+/*
+ * gedit-theatrics-actor.h
+ * This file is part of gedit
+ *
+ * Copyright (C) 2010 - Ignacio Casal Quinteiro
+ *
+ * Based on Aaron Bockover <abockover novell com> work.
+ *
+ * gedit is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * gedit 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 gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifndef __GEDIT_THEATRICS_ACTOR_H__
+#define __GEDIT_THEATRICS_ACTOR_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GEDIT_TYPE_THEATRICS_ACTOR (gedit_theatrics_actor_get_type ())
+#define GEDIT_THEATRICS_ACTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_THEATRICS_ACTOR, GeditTheatricsActor))
+#define GEDIT_THEATRICS_ACTOR_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_THEATRICS_ACTOR, GeditTheatricsActor const))
+#define GEDIT_THEATRICS_ACTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GEDIT_TYPE_THEATRICS_ACTOR, GeditTheatricsActorClass))
+#define GEDIT_IS_THEATRICS_ACTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEDIT_TYPE_THEATRICS_ACTOR))
+#define GEDIT_IS_THEATRICS_ACTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEDIT_TYPE_THEATRICS_ACTOR))
+#define GEDIT_THEATRICS_ACTOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GEDIT_TYPE_THEATRICS_ACTOR, GeditTheatricsActorClass))
+
+typedef struct _GeditTheatricsActor GeditTheatricsActor;
+typedef struct _GeditTheatricsActorClass GeditTheatricsActorClass;
+typedef struct _GeditTheatricsActorPrivate GeditTheatricsActorPrivate;
+
+struct _GeditTheatricsActor
+{
+ GObject parent;
+
+ GeditTheatricsActorPrivate *priv;
+};
+
+struct _GeditTheatricsActorClass
+{
+ GObjectClass parent_class;
+};
+
+GType gedit_theatrics_actor_get_type (void) G_GNUC_CONST;
+
+GeditTheatricsActor *gedit_theatrics_actor_new (GObject *target,
+ guint duration);
+
+void gedit_theatrics_actor_reset (GeditTheatricsActor *actor,
+ guint duration);
+
+void gedit_theatrics_actor_step (GeditTheatricsActor *actor);
+
+GObject *gedit_theatrics_actor_get_target (GeditTheatricsActor *actor);
+
+gboolean gedit_theatrics_actor_get_expired (GeditTheatricsActor *actor);
+
+gboolean gedit_theatrics_actor_get_can_expire (GeditTheatricsActor *actor);
+
+void gedit_theatrics_actor_set_can_expire (GeditTheatricsActor *actor,
+ gboolean can_expire);
+
+guint gedit_theatrics_actor_get_duration (GeditTheatricsActor *actor);
+
+GTimeVal gedit_theatrics_actor_get_start_time (GeditTheatricsActor *actor);
+
+gdouble gedit_theatrics_actor_get_frames (GeditTheatricsActor *actor);
+
+gdouble gedit_theatrics_actor_get_frames_per_second
+ (GeditTheatricsActor *actor);
+
+gdouble gedit_theatrics_actor_get_percent (GeditTheatricsActor *actor);
+
+G_END_DECLS
+
+#endif /* __GEDIT_THEATRICS_ACTOR_H__ */
+
+/* ex:ts=8:noet: */
diff --git a/gedit/theatrics/gedit-theatrics-animated-widget.c b/gedit/theatrics/gedit-theatrics-animated-widget.c
new file mode 100644
index 0000000..826aec1
--- /dev/null
+++ b/gedit/theatrics/gedit-theatrics-animated-widget.c
@@ -0,0 +1,643 @@
+/*
+ * gedit-theatrics-animated-widget.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 2010 - Ignacio Casal Quinteiro
+ *
+ * Based on Scott Peterson <lunchtimemama gmail com> work.
+ *
+ * gedit is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * gedit 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 gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#include "gedit-theatrics-animated-widget.h"
+#include "gedit-theatrics-enum-types.h"
+
+
+#define GEDIT_THEATRICS_ANIMATED_WIDGET_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GEDIT_TYPE_THEATRICS_ANIMATED_WIDGET, GeditTheatricsAnimatedWidgetPrivate))
+
+struct _GeditTheatricsAnimatedWidgetPrivate
+{
+ GtkWidget *widget;
+ GeditTheatricsChoreographerEasing easing;
+ GeditTheatricsChoreographerBlocking blocking;
+ GeditTheatricsAnimationState animation_state;
+ GtkOrientation orientation;
+ guint duration;
+ gdouble bias;
+ gdouble percent;
+ GtkAllocation widget_alloc;
+
+ cairo_surface_t *surface;
+
+ gint width;
+ gint height;
+ gint start_padding;
+ gint end_padding;
+};
+
+enum
+{
+ PROP_0,
+ PROP_WIDGET,
+ PROP_EASING,
+ PROP_BLOCKING,
+ PROP_ANIMATION_STATE,
+ PROP_DURATION,
+ PROP_PERCENT,
+ PROP_ORIENTATION
+};
+
+enum
+{
+ REMOVE_CORE,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+G_DEFINE_TYPE_EXTENDED (GeditTheatricsAnimatedWidget,
+ gedit_theatrics_animated_widget,
+ GTK_TYPE_BIN,
+ 0,
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE,
+ NULL))
+
+static void
+on_widget_destroyed (GtkWidget *widget,
+ GeditTheatricsAnimatedWidget *aw)
+{
+ GdkWindow *window;
+ cairo_t *img_cr;
+ cairo_t *cr;
+ cairo_surface_t *surface;
+
+ if (!gtk_widget_get_realized (GTK_WIDGET (aw)))
+ return;
+
+ aw->priv->width = aw->priv->widget_alloc.width;
+ aw->priv->height = aw->priv->widget_alloc.height;
+
+ aw->priv->surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+ aw->priv->width,
+ aw->priv->height);
+
+ img_cr = cairo_create (aw->priv->surface);
+
+ window = gtk_widget_get_window (GTK_WIDGET (aw));
+
+ cr = gdk_cairo_create (GDK_DRAWABLE (window));
+ surface = cairo_get_target (cr);
+
+ cairo_set_source_surface (img_cr, surface,
+ aw->priv->widget_alloc.x,
+ aw->priv->widget_alloc.y);
+
+ cairo_paint (img_cr);
+
+ cairo_destroy (img_cr);
+ cairo_destroy (cr);
+
+ if (aw->priv->animation_state != GEDIT_THEATRICS_ANIMATION_STATE_GOING)
+ {
+ g_signal_emit (G_OBJECT (aw), signals[REMOVE_CORE], 0);
+ }
+}
+
+static void
+set_widget (GeditTheatricsAnimatedWidget *aw,
+ GtkWidget *widget)
+{
+ if (widget == NULL)
+ return;
+
+ aw->priv->widget = widget;
+ gtk_widget_set_parent (widget, GTK_WIDGET (aw));
+
+ g_signal_connect (widget, "destroy",
+ G_CALLBACK (on_widget_destroyed),
+ aw);
+}
+
+static void
+gedit_theatrics_animated_widget_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (gedit_theatrics_animated_widget_parent_class)->finalize (object);
+}
+
+static void
+gedit_theatrics_animated_widget_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GeditTheatricsAnimatedWidget *aw = GEDIT_THEATRICS_ANIMATED_WIDGET (object);
+
+ switch (prop_id)
+ {
+ case PROP_WIDGET:
+ g_value_set_object (value, aw->priv->widget);
+ break;
+ case PROP_EASING:
+ g_value_set_enum (value, aw->priv->easing);
+ break;
+ case PROP_BLOCKING:
+ g_value_set_enum (value, aw->priv->blocking);
+ break;
+ case PROP_ANIMATION_STATE:
+ g_value_set_enum (value, aw->priv->animation_state);
+ break;
+ case PROP_DURATION:
+ g_value_set_uint (value, aw->priv->duration);
+ break;
+ case PROP_PERCENT:
+ g_value_set_double (value, aw->priv->percent);
+ break;
+ case PROP_ORIENTATION:
+ g_value_set_enum (value, aw->priv->orientation);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gedit_theatrics_animated_widget_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GeditTheatricsAnimatedWidget *aw = GEDIT_THEATRICS_ANIMATED_WIDGET (object);
+
+ switch (prop_id)
+ {
+ case PROP_WIDGET:
+ {
+ set_widget (aw, g_value_get_object (value));
+ break;
+ }
+ case PROP_EASING:
+ gedit_theatrics_animated_widget_set_easing (aw,
+ g_value_get_enum (value));
+ break;
+ case PROP_BLOCKING:
+ gedit_theatrics_animated_widget_set_blocking (aw,
+ g_value_get_enum (value));
+ break;
+ case PROP_ANIMATION_STATE:
+ gedit_theatrics_animated_widget_set_animation_state (aw,
+ g_value_get_enum (value));
+ break;
+ case PROP_DURATION:
+ gedit_theatrics_animated_widget_set_duration (aw,
+ g_value_get_uint (value));
+ break;
+ case PROP_PERCENT:
+ gedit_theatrics_animated_widget_set_percent (aw,
+ g_value_get_double (value));
+ break;
+ case PROP_ORIENTATION:
+ aw->priv->orientation = g_value_get_enum (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gedit_theatrics_animated_widget_realize (GtkWidget *widget)
+{
+ GdkWindowAttr attributes;
+ GdkWindow *parent_window;
+ GdkWindow *window;
+ GtkStyle *style;
+
+ gtk_widget_set_realized (widget, TRUE);
+
+ parent_window = gtk_widget_get_parent_window (widget);
+ style = gtk_widget_get_style (widget);
+
+ attributes.window_type = GDK_WINDOW_CHILD;
+ attributes.wclass = GDK_INPUT_OUTPUT;
+ attributes.event_mask = GDK_EXPOSURE_MASK;
+
+ window = gdk_window_new (parent_window, &attributes, 0);
+ gdk_window_set_user_data (window, widget);
+ gtk_widget_set_window (widget, window);
+ gdk_window_set_back_pixmap (window, NULL, FALSE);
+ style = gtk_style_attach (style, window);
+ gtk_widget_set_style (widget, style);
+ gtk_style_set_background (style, window, GTK_STATE_NORMAL);
+}
+
+static void
+gedit_theatrics_animated_widget_size_request (GtkWidget *widget,
+ GtkRequisition *requisition)
+{
+ GeditTheatricsAnimatedWidget *aw = GEDIT_THEATRICS_ANIMATED_WIDGET (widget);
+ gint width;
+ gint height;
+
+ if (aw->priv->widget != NULL)
+ {
+ GtkRequisition req;
+
+ gtk_widget_size_request (aw->priv->widget, &req);
+ aw->priv->widget_alloc.width = req.width;
+ aw->priv->widget_alloc.height = req.height;
+ }
+
+ if (aw->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ width = gedit_theatrics_choreographer_pixel_compose (aw->priv->percent,
+ aw->priv->widget_alloc.width +
+ aw->priv->start_padding +
+ aw->priv->end_padding,
+ aw->priv->easing);
+ height = aw->priv->widget_alloc.height;
+ }
+ else
+ {
+ width = aw->priv->widget_alloc.width;
+ height = gedit_theatrics_choreographer_pixel_compose (aw->priv->percent,
+ aw->priv->widget_alloc.height +
+ aw->priv->start_padding +
+ aw->priv->end_padding,
+ aw->priv->easing);
+ }
+
+ requisition->width = width;
+ requisition->height = height;
+}
+
+static void
+gedit_theatrics_animated_widget_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ GeditTheatricsAnimatedWidget *aw = GEDIT_THEATRICS_ANIMATED_WIDGET (widget);
+
+ GTK_WIDGET_CLASS (gedit_theatrics_animated_widget_parent_class)->size_allocate (widget, allocation);
+
+ if (aw->priv->widget != NULL)
+ {
+ if (aw->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ aw->priv->widget_alloc.height = allocation->height;
+ aw->priv->widget_alloc.x = aw->priv->start_padding;
+
+ if (aw->priv->blocking == GEDIT_THEATRICS_CHOREOGRAPHER_BLOCKING_DOWNSTAGE)
+ {
+ aw->priv->widget_alloc.x += allocation->width - aw->priv->widget_alloc.width;
+ }
+ }
+ else
+ {
+ aw->priv->widget_alloc.width = allocation->width;
+ aw->priv->widget_alloc.y = aw->priv->start_padding;
+
+ if (aw->priv->blocking == GEDIT_THEATRICS_CHOREOGRAPHER_BLOCKING_DOWNSTAGE)
+ {
+ aw->priv->widget_alloc.y = allocation->height - aw->priv->widget_alloc.height;
+ }
+ }
+
+ if (aw->priv->widget_alloc.height > 0 && aw->priv->widget_alloc.width > 0)
+ {
+ gtk_widget_size_allocate (aw->priv->widget,
+ &aw->priv->widget_alloc);
+ }
+ }
+}
+
+static gboolean
+gedit_theatrics_animated_widget_expose_event (GtkWidget *widget,
+ GdkEventExpose *event)
+{
+ GeditTheatricsAnimatedWidget *aw = GEDIT_THEATRICS_ANIMATED_WIDGET (widget);
+
+ if (aw->priv->surface != NULL)
+ {
+ /* Do not scale if the size is 0 */
+ if (aw->priv->width > 0 && aw->priv->height > 0)
+ {
+ cairo_t *cr;
+ cr = gdk_cairo_create (event->window);
+
+ cairo_scale (cr,
+ aw->priv->widget_alloc.width / aw->priv->width,
+ aw->priv->widget_alloc.height / aw->priv->height);
+ cairo_set_source_surface (cr, aw->priv->surface, 0, 0);
+
+ cairo_paint (cr);
+ cairo_destroy (cr);
+ }
+
+ return TRUE;
+ }
+ else
+ {
+ return GTK_WIDGET_CLASS (gedit_theatrics_animated_widget_parent_class)->expose_event (widget, event);
+ }
+}
+
+static void
+gedit_theatrics_animated_widget_remove (GtkContainer *container,
+ GtkWidget *widget)
+{
+ GeditTheatricsAnimatedWidget *aw = GEDIT_THEATRICS_ANIMATED_WIDGET (container);
+
+ gtk_widget_unparent (widget);
+ aw->priv->widget = NULL;
+}
+
+static void
+gedit_theatrics_animated_widget_forall (GtkContainer *container,
+ gboolean include_internals,
+ GtkCallback callback,
+ gpointer callback_data)
+{
+ GeditTheatricsAnimatedWidget *aw = GEDIT_THEATRICS_ANIMATED_WIDGET (container);
+
+ if (aw->priv->widget != NULL)
+ {
+ callback (aw->priv->widget, callback_data);
+ }
+}
+
+static void
+gedit_theatrics_animated_widget_class_init (GeditTheatricsAnimatedWidgetClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
+
+ object_class->finalize = gedit_theatrics_animated_widget_finalize;
+ object_class->get_property = gedit_theatrics_animated_widget_get_property;
+ object_class->set_property = gedit_theatrics_animated_widget_set_property;
+
+ widget_class->realize = gedit_theatrics_animated_widget_realize;
+ widget_class->size_request = gedit_theatrics_animated_widget_size_request;
+ widget_class->size_allocate = gedit_theatrics_animated_widget_size_allocate;
+ widget_class->expose_event = gedit_theatrics_animated_widget_expose_event;
+
+ container_class->remove = gedit_theatrics_animated_widget_remove;
+ container_class->forall = gedit_theatrics_animated_widget_forall;
+
+ g_object_class_install_property (object_class, PROP_WIDGET,
+ g_param_spec_object ("widget",
+ "Widget",
+ "The Widget",
+ GTK_TYPE_WIDGET,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (object_class, PROP_EASING,
+ g_param_spec_enum ("easing",
+ "Easing",
+ "The Easing",
+ GEDIT_TYPE_THEATRICS_CHOREOGRAPHER_EASING,
+ GEDIT_THEATRICS_CHOREOGRAPHER_EASING_LINEAR,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (object_class, PROP_BLOCKING,
+ g_param_spec_enum ("blocking",
+ "Blocking",
+ "The Blocking",
+ GEDIT_TYPE_THEATRICS_CHOREOGRAPHER_BLOCKING,
+ GEDIT_THEATRICS_CHOREOGRAPHER_BLOCKING_DOWNSTAGE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (object_class, PROP_ANIMATION_STATE,
+ g_param_spec_enum ("animation-state",
+ "Animation State",
+ "The Animation State",
+ GEDIT_TYPE_THEATRICS_ANIMATION_STATE,
+ GEDIT_THEATRICS_ANIMATION_STATE_COMING,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (object_class, PROP_DURATION,
+ g_param_spec_uint ("duration",
+ "Duration",
+ "The duration",
+ 0,
+ G_MAXUINT,
+ 0,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (object_class, PROP_PERCENT,
+ g_param_spec_double ("percent",
+ "Percent",
+ "The percent",
+ 0,
+ G_MAXDOUBLE,
+ 0.0,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_override_property (object_class,
+ PROP_ORIENTATION,
+ "orientation");
+
+ signals[REMOVE_CORE] =
+ g_signal_new ("remove-core",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GeditTheatricsAnimatedWidgetClass, remove_core),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+ g_type_class_add_private (object_class, sizeof (GeditTheatricsAnimatedWidgetPrivate));
+}
+
+static void
+gedit_theatrics_animated_widget_init (GeditTheatricsAnimatedWidget *aw)
+{
+ aw->priv = GEDIT_THEATRICS_ANIMATED_WIDGET_GET_PRIVATE (aw);
+
+ gtk_widget_set_has_window (GTK_WIDGET (aw), TRUE);
+
+ aw->priv->orientation = GTK_ORIENTATION_HORIZONTAL;
+ aw->priv->bias = 1.0;
+}
+
+GeditTheatricsAnimatedWidget *
+gedit_theatrics_animated_widget_new (GtkWidget *widget,
+ guint duration,
+ GeditTheatricsChoreographerEasing easing,
+ GeditTheatricsChoreographerBlocking blocking,
+ GtkOrientation orientation)
+{
+ return g_object_new (GEDIT_TYPE_THEATRICS_ANIMATED_WIDGET,
+ "widget", widget,
+ "duration", duration,
+ "easing", easing,
+ "blocking", blocking,
+ "orientation", orientation,
+ NULL);
+}
+
+GtkWidget *
+gedit_theatrics_animated_widget_get_widget (GeditTheatricsAnimatedWidget *aw)
+{
+ g_return_val_if_fail (GEDIT_IS_THEATRICS_ANIMATED_WIDGET (aw), NULL);
+
+ return aw->priv->widget;
+}
+
+GeditTheatricsChoreographerEasing
+gedit_theatrics_animated_widget_get_easing (GeditTheatricsAnimatedWidget *aw)
+{
+ g_return_val_if_fail (GEDIT_IS_THEATRICS_ANIMATED_WIDGET (aw), GEDIT_THEATRICS_CHOREOGRAPHER_EASING_LINEAR);
+
+ return aw->priv->easing;
+}
+
+void
+gedit_theatrics_animated_widget_set_easing (GeditTheatricsAnimatedWidget *aw,
+ GeditTheatricsChoreographerEasing easing)
+{
+ g_return_if_fail (GEDIT_IS_THEATRICS_ANIMATED_WIDGET (aw));
+
+ if (aw->priv->easing != easing)
+ {
+ aw->priv->easing = easing;
+
+ g_object_notify (G_OBJECT (aw), "easing");
+ }
+}
+
+GeditTheatricsChoreographerBlocking
+gedit_theatrics_animated_widget_get_blocking (GeditTheatricsAnimatedWidget *aw)
+{
+ g_return_val_if_fail (GEDIT_IS_THEATRICS_ANIMATED_WIDGET (aw), GEDIT_THEATRICS_CHOREOGRAPHER_BLOCKING_DOWNSTAGE);
+
+ return aw->priv->blocking;
+}
+
+void
+gedit_theatrics_animated_widget_set_blocking (GeditTheatricsAnimatedWidget *aw,
+ GeditTheatricsChoreographerBlocking blocking)
+{
+ g_return_if_fail (GEDIT_IS_THEATRICS_ANIMATED_WIDGET (aw));
+
+ if (aw->priv->blocking != blocking)
+ {
+ aw->priv->blocking = blocking;
+
+ g_object_notify (G_OBJECT (aw), "blocking");
+ }
+}
+
+GeditTheatricsAnimationState
+gedit_theatrics_animated_widget_get_animation_state (GeditTheatricsAnimatedWidget *aw)
+{
+ g_return_val_if_fail (GEDIT_IS_THEATRICS_ANIMATED_WIDGET (aw), GEDIT_THEATRICS_ANIMATION_STATE_COMING);
+
+ return aw->priv->animation_state;
+}
+
+void
+gedit_theatrics_animated_widget_set_animation_state (GeditTheatricsAnimatedWidget *aw,
+ GeditTheatricsAnimationState animation_state)
+{
+ g_return_if_fail (GEDIT_IS_THEATRICS_ANIMATED_WIDGET (aw));
+
+ if (aw->priv->animation_state != animation_state)
+ {
+ aw->priv->animation_state = animation_state;
+
+ g_object_notify (G_OBJECT (aw), "animation-state");
+ }
+}
+
+guint
+gedit_theatrics_animated_widget_get_duration (GeditTheatricsAnimatedWidget *aw)
+{
+ g_return_val_if_fail (GEDIT_IS_THEATRICS_ANIMATED_WIDGET (aw), 0);
+
+ return aw->priv->duration;
+}
+
+void
+gedit_theatrics_animated_widget_set_duration (GeditTheatricsAnimatedWidget *aw,
+ guint duration)
+{
+ g_return_if_fail (GEDIT_IS_THEATRICS_ANIMATED_WIDGET (aw));
+
+ if (aw->priv->duration != duration)
+ {
+ aw->priv->duration = duration;
+
+ g_object_notify (G_OBJECT (aw), "duration");
+ }
+}
+
+gdouble
+gedit_theatrics_animated_widget_get_percent (GeditTheatricsAnimatedWidget *aw)
+{
+ g_return_val_if_fail (GEDIT_IS_THEATRICS_ANIMATED_WIDGET (aw), 0.0);
+
+ return aw->priv->duration;
+}
+
+void
+gedit_theatrics_animated_widget_set_percent (GeditTheatricsAnimatedWidget *aw,
+ gdouble percent)
+{
+ g_return_if_fail (GEDIT_IS_THEATRICS_ANIMATED_WIDGET (aw));
+
+ if (aw->priv->percent != percent)
+ {
+ aw->priv->percent = aw->priv->bias * percent;
+
+ g_object_notify (G_OBJECT (aw), "percent");
+
+ gtk_widget_queue_resize_no_redraw (GTK_WIDGET (aw));
+ }
+}
+
+void
+gedit_theatrics_animated_widget_set_bias (GeditTheatricsAnimatedWidget *aw,
+ gdouble bias)
+{
+ g_return_if_fail (GEDIT_IS_THEATRICS_ANIMATED_WIDGET (aw));
+
+ aw->priv->bias = bias;
+}
+
+void
+gedit_theatrics_animated_widget_set_end_padding (GeditTheatricsAnimatedWidget *aw,
+ gint end_padding)
+{
+ g_return_if_fail (GEDIT_IS_THEATRICS_ANIMATED_WIDGET (aw));
+
+ aw->priv->end_padding = end_padding;
+}
+
+/* ex:ts=8:noet: */
diff --git a/gedit/theatrics/gedit-theatrics-animated-widget.h b/gedit/theatrics/gedit-theatrics-animated-widget.h
new file mode 100644
index 0000000..603ce6c
--- /dev/null
+++ b/gedit/theatrics/gedit-theatrics-animated-widget.h
@@ -0,0 +1,108 @@
+/*
+ * gedit-theatrics-animated-widget.h
+ * This file is part of gedit
+ *
+ * Copyright (C) 2010 - Ignacio Casal Quinteiro
+ *
+ * Based on Scott Peterson <lunchtimemama gmail com> work.
+ *
+ * gedit is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * gedit 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 gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifndef __GEDIT_THEATRICS_ANIMATED_WIDGET_H__
+#define __GEDIT_THEATRICS_ANIMATED_WIDGET_H__
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include "gedit-theatrics-animation.h"
+#include "gedit-theatrics-choreographer.h"
+
+G_BEGIN_DECLS
+
+#define GEDIT_TYPE_THEATRICS_ANIMATED_WIDGET (gedit_theatrics_animated_widget_get_type ())
+#define GEDIT_THEATRICS_ANIMATED_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_THEATRICS_ANIMATED_WIDGET, GeditTheatricsAnimatedWidget))
+#define GEDIT_THEATRICS_ANIMATED_WIDGET_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_THEATRICS_ANIMATED_WIDGET, GeditTheatricsAnimatedWidget const))
+#define GEDIT_THEATRICS_ANIMATED_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GEDIT_TYPE_THEATRICS_ANIMATED_WIDGET, GeditTheatricsAnimatedWidgetClass))
+#define GEDIT_IS_THEATRICS_ANIMATED_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEDIT_TYPE_THEATRICS_ANIMATED_WIDGET))
+#define GEDIT_IS_THEATRICS_ANIMATED_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEDIT_TYPE_THEATRICS_ANIMATED_WIDGET))
+#define GEDIT_THEATRICS_ANIMATED_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GEDIT_TYPE_THEATRICS_ANIMATED_WIDGET, GeditTheatricsAnimatedWidgetClass))
+
+typedef struct _GeditTheatricsAnimatedWidget GeditTheatricsAnimatedWidget;
+typedef struct _GeditTheatricsAnimatedWidgetClass GeditTheatricsAnimatedWidgetClass;
+typedef struct _GeditTheatricsAnimatedWidgetPrivate GeditTheatricsAnimatedWidgetPrivate;
+
+struct _GeditTheatricsAnimatedWidget
+{
+ GtkBin parent;
+
+ GeditTheatricsAnimatedWidgetPrivate *priv;
+};
+
+struct _GeditTheatricsAnimatedWidgetClass
+{
+ GtkBinClass parent_class;
+
+ void (* remove_core) (GeditTheatricsAnimatedWidget *aw);
+};
+
+GType gedit_theatrics_animated_widget_get_type (void) G_GNUC_CONST;
+
+GeditTheatricsAnimatedWidget *gedit_theatrics_animated_widget_new (GtkWidget *widget,
+ guint duration,
+ GeditTheatricsChoreographerEasing easing,
+ GeditTheatricsChoreographerBlocking blocking,
+ GtkOrientation orientation);
+
+GtkWidget *gedit_theatrics_animated_widget_get_widget (GeditTheatricsAnimatedWidget *aw);
+
+GeditTheatricsChoreographerEasing
+ gedit_theatrics_animated_widget_get_easing (GeditTheatricsAnimatedWidget *aw);
+
+void gedit_theatrics_animated_widget_set_easing (GeditTheatricsAnimatedWidget *aw,
+ GeditTheatricsChoreographerEasing easing);
+
+GeditTheatricsChoreographerBlocking
+ gedit_theatrics_animated_widget_get_blocking (GeditTheatricsAnimatedWidget *aw);
+
+void gedit_theatrics_animated_widget_set_blocking (GeditTheatricsAnimatedWidget *aw,
+ GeditTheatricsChoreographerBlocking blocking);
+
+GeditTheatricsAnimationState gedit_theatrics_animated_widget_get_animation_state
+ (GeditTheatricsAnimatedWidget *aw);
+
+void gedit_theatrics_animated_widget_set_animation_state
+ (GeditTheatricsAnimatedWidget *aw,
+ GeditTheatricsAnimationState animation_state);
+
+guint gedit_theatrics_animated_widget_get_duration (GeditTheatricsAnimatedWidget *aw);
+
+void gedit_theatrics_animated_widget_set_duration (GeditTheatricsAnimatedWidget *aw,
+ guint duration);
+
+gdouble gedit_theatrics_animated_widget_get_percent (GeditTheatricsAnimatedWidget *aw);
+
+void gedit_theatrics_animated_widget_set_percent (GeditTheatricsAnimatedWidget *aw,
+ gdouble percent);
+
+void gedit_theatrics_animated_widget_set_bias (GeditTheatricsAnimatedWidget *aw,
+ gdouble bias);
+
+void gedit_theatrics_animated_widget_set_end_padding(GeditTheatricsAnimatedWidget *aw,
+ gint end_padding);
+
+G_END_DECLS
+
+#endif /* __GEDIT_THEATRICS_ANIMATED_WIDGET_H__ */
diff --git a/gedit/theatrics/gedit-theatrics-choreographer.c b/gedit/theatrics/gedit-theatrics-choreographer.c
new file mode 100644
index 0000000..1dbf582
--- /dev/null
+++ b/gedit/theatrics/gedit-theatrics-choreographer.c
@@ -0,0 +1,85 @@
+/*
+ * gedit-theatrics-choreographer.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 2010 - Ignacio Casal Quinteiro
+ *
+ * Based on Scott Peterson <lunchtimemama gmail com> work.
+ *
+ * gedit is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * gedit 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 gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#include <math.h>
+#include "gedit-theatrics-choreographer.h"
+
+gint
+gedit_theatrics_choreographer_pixel_compose (gdouble percent,
+ gint size,
+ GeditTheatricsChoreographerEasing easing)
+{
+ return (gint)round (gedit_theatrics_choreographer_compose_with_scale (percent, size, easing));
+}
+
+gdouble
+gedit_theatrics_choreographer_compose_with_scale (gdouble percent,
+ gdouble scale,
+ GeditTheatricsChoreographerEasing easing)
+{
+ return scale * gedit_theatrics_choreographer_compose (percent, easing);
+}
+
+gdouble
+gedit_theatrics_choreographer_compose (gdouble percent,
+ GeditTheatricsChoreographerEasing easing)
+{
+ g_return_val_if_fail (percent >= 0.0 && percent <= 1.0, 0.0);
+
+ switch (easing)
+ {
+ case GEDIT_THEATRICS_CHOREOGRAPHER_EASING_QUADRATIC_IN:
+ return percent * percent;
+
+ case GEDIT_THEATRICS_CHOREOGRAPHER_EASING_QUADRATIC_OUT:
+ return -1.0 * percent * (percent - 2.0);
+
+ case GEDIT_THEATRICS_CHOREOGRAPHER_EASING_QUADRATIC_IN_OUT:
+ percent *= 2.0;
+ return percent < 1.0
+ ? percent * percent * 0.5
+ : -0.5 * ((percent - 1.0) * (percent - 2.0) - 1.0);
+
+ case GEDIT_THEATRICS_CHOREOGRAPHER_EASING_EXPONENTIAL_IN:
+ return pow (2.0, 10.0 * (percent - 1.0));
+
+ case GEDIT_THEATRICS_CHOREOGRAPHER_EASING_EXPONENTIAL_OUT:
+ return -pow (2.0, -10.0 * percent) + 1.0;
+
+ case GEDIT_THEATRICS_CHOREOGRAPHER_EASING_EXPONENTIAL_IN_OUT:
+ percent *= 2.0;
+ return percent < 1.0
+ ? 0.5 * pow (2.0, 10.0 * (percent - 1.0))
+ : 0.5 * (-pow (2.0, -10.0 * (percent - 1.0)) + 2.0);
+
+ case GEDIT_THEATRICS_CHOREOGRAPHER_EASING_SINE:
+ return sin (percent * G_PI);
+
+ case GEDIT_THEATRICS_CHOREOGRAPHER_EASING_LINEAR:
+ default:
+ return percent;
+ }
+}
+
+/* ex:ts=8:noet: */
diff --git a/gedit/theatrics/gedit-theatrics-choreographer.h b/gedit/theatrics/gedit-theatrics-choreographer.h
new file mode 100644
index 0000000..310cc8f
--- /dev/null
+++ b/gedit/theatrics/gedit-theatrics-choreographer.h
@@ -0,0 +1,74 @@
+/*
+ * gedit-theatrics-choreographer.h
+ * This file is part of gedit
+ *
+ * Copyright (C) 2010 - Ignacio Casal Quinteiro
+ *
+ * Based on Scott Peterson <lunchtimemama gmail com> work.
+ *
+ * gedit is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * gedit 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 gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifndef __GEDIT_THEATRICS_CHOREOGRAPHER_H__
+#define __GEDIT_THEATRICS_CHOREOGRAPHER_H__
+
+#include <glib.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+typedef enum
+{
+ GEDIT_THEATRICS_ANIMATION_STATE_COMING,
+ GEDIT_THEATRICS_ANIMATION_STATE_IDLE,
+ GEDIT_THEATRICS_ANIMATION_STATE_INTENDING_TO_GO,
+ GEDIT_THEATRICS_ANIMATION_STATE_GOING
+} GeditTheatricsAnimationState;
+
+typedef enum
+{
+ GEDIT_THEATRICS_CHOREOGRAPHER_BLOCKING_UPSTAGE,
+ GEDIT_THEATRICS_CHOREOGRAPHER_BLOCKING_DOWNSTAGE
+} GeditTheatricsChoreographerBlocking;
+
+typedef enum
+{
+ GEDIT_THEATRICS_CHOREOGRAPHER_EASING_LINEAR,
+ GEDIT_THEATRICS_CHOREOGRAPHER_EASING_QUADRATIC_IN,
+ GEDIT_THEATRICS_CHOREOGRAPHER_EASING_QUADRATIC_OUT,
+ GEDIT_THEATRICS_CHOREOGRAPHER_EASING_QUADRATIC_IN_OUT,
+ GEDIT_THEATRICS_CHOREOGRAPHER_EASING_EXPONENTIAL_IN,
+ GEDIT_THEATRICS_CHOREOGRAPHER_EASING_EXPONENTIAL_OUT,
+ GEDIT_THEATRICS_CHOREOGRAPHER_EASING_EXPONENTIAL_IN_OUT,
+ GEDIT_THEATRICS_CHOREOGRAPHER_EASING_SINE
+} GeditTheatricsChoreographerEasing;
+
+gint gedit_theatrics_choreographer_pixel_compose (gdouble percent,
+ gint size,
+ GeditTheatricsChoreographerEasing easing);
+
+gdouble gedit_theatrics_choreographer_compose_with_scale (gdouble percent,
+ gdouble scale,
+ GeditTheatricsChoreographerEasing easing);
+
+gdouble gedit_theatrics_choreographer_compose (gdouble percent,
+ GeditTheatricsChoreographerEasing easing);
+
+G_END_DECLS
+
+#endif /* __GEDIT_THEATRICS_CHOREOGRAPHER_H__ */
+
+/* ex:ts=8:noet: */
diff --git a/gedit/theatrics/gedit-theatrics-enum-types.c.template b/gedit/theatrics/gedit-theatrics-enum-types.c.template
new file mode 100644
index 0000000..9d53bbc
--- /dev/null
+++ b/gedit/theatrics/gedit-theatrics-enum-types.c.template
@@ -0,0 +1,39 @@
+/*** BEGIN file-header ***/
+#include "gedit-theatrics-enum-types.h"
+
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+/* enumerations from "@filename@" */
+#include "@filename@"
+
+/*** END file-production ***/
+
+/*** BEGIN value-header ***/
+GType
+ enum_name@_get_type (void)
+{
+ static GType the_type = 0;
+
+ if (the_type == 0)
+ {
+ static const G Type@Value values[] = {
+/*** END value-header ***/
+
+/*** BEGIN value-production ***/
+ { @VALUENAME@,
+ "@VALUENAME@",
+ "@valuenick@" },
+/*** END value-production ***/
+
+/*** BEGIN value-tail ***/
+ { 0, NULL, NULL }
+ };
+ the_type = g_ type@_register_static (
+ g_intern_static_string ("@EnumName@"),
+ values);
+ }
+ return the_type;
+}
+
+/*** END value-tail ***/
diff --git a/gedit/theatrics/gedit-theatrics-enum-types.h.template b/gedit/theatrics/gedit-theatrics-enum-types.h.template
new file mode 100644
index 0000000..4eb11eb
--- /dev/null
+++ b/gedit/theatrics/gedit-theatrics-enum-types.h.template
@@ -0,0 +1,27 @@
+/*** BEGIN file-header ***/
+#ifndef __GEDIT_THEATRICS_ENUM_TYPES_H__
+#define __GEDIT_THEATRICS_ENUM_TYPES_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+/* Enumerations from "@filename@" */
+
+/*** END file-production ***/
+
+/*** BEGIN enumeration-production ***/
+#define GEDIT_TYPE_ ENUMSHORT@ (@enum_name _get_type())
+GType @enum_name _get_type (void) G_GNUC_CONST;
+
+/*** END enumeration-production ***/
+
+/*** BEGIN file-tail ***/
+G_END_DECLS
+
+#endif /* __GEDIT_ENUM_TYPES_H__ */
+/*** END file-tail ***/
+
diff --git a/gedit/theatrics/gedit-theatrics-marshal.list b/gedit/theatrics/gedit-theatrics-marshal.list
new file mode 100644
index 0000000..38076d6
--- /dev/null
+++ b/gedit/theatrics/gedit-theatrics-marshal.list
@@ -0,0 +1 @@
+VOID:OBJECT,OBJECT
diff --git a/gedit/theatrics/gedit-theatrics-stage.c b/gedit/theatrics/gedit-theatrics-stage.c
new file mode 100644
index 0000000..fed1b05
--- /dev/null
+++ b/gedit/theatrics/gedit-theatrics-stage.c
@@ -0,0 +1,313 @@
+/*
+ * gedit-theatrics-stage.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 2010 - Ignacio Casal Quinteiro
+ *
+ * Based on Aaron Bockover <abockover novell com> work.
+ *
+ * gedit is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * gedit 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 gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#include "gedit-theatrics-stage.h"
+
+
+#define DEFAULT_UPDATE_FREQUENCY 30
+#define DEFAULT_DURATION 1000
+
+#define GEDIT_THEATRICS_STAGE_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GEDIT_TYPE_THEATRICS_STAGE, GeditTheatricsStagePrivate))
+
+struct _GeditTheatricsStagePrivate
+{
+ GHashTable *actors;
+ guint timeout_id;
+ guint update_frequency;
+ guint actor_duration;
+
+ guint playing : 1;
+};
+
+enum
+{
+ PROP_0,
+ PROP_ACTOR_DURATION
+};
+
+enum
+{
+ ACTOR_STEP,
+ ITERATION,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+G_DEFINE_TYPE (GeditTheatricsStage, gedit_theatrics_stage, G_TYPE_OBJECT)
+
+static void
+gedit_theatrics_stage_dispose (GObject *object)
+{
+ GeditTheatricsStage *stage = GEDIT_THEATRICS_STAGE (object);
+
+ if (stage->priv->timeout_id != 0)
+ {
+ g_source_remove (stage->priv->timeout_id);
+ stage->priv->timeout_id = 0;
+ }
+
+ G_OBJECT_CLASS (gedit_theatrics_stage_parent_class)->dispose (object);
+}
+
+static void
+gedit_theatrics_stage_finalize (GObject *object)
+{
+ GeditTheatricsStage *stage = GEDIT_THEATRICS_STAGE (object);
+
+ g_hash_table_destroy (stage->priv->actors);
+
+ G_OBJECT_CLASS (gedit_theatrics_stage_parent_class)->finalize (object);
+}
+
+static void
+gedit_theatrics_stage_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GeditTheatricsStage *stage = GEDIT_THEATRICS_STAGE (object);
+
+ switch (prop_id)
+ {
+ case PROP_ACTOR_DURATION:
+ g_value_set_uint (value, stage->priv->actor_duration);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gedit_theatrics_stage_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GeditTheatricsStage *stage = GEDIT_THEATRICS_STAGE (object);
+
+ switch (prop_id)
+ {
+ case PROP_ACTOR_DURATION:
+ stage->priv->actor_duration = g_value_get_uint (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gedit_theatrics_stage_class_init (GeditTheatricsStageClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = gedit_theatrics_stage_dispose;
+ object_class->finalize = gedit_theatrics_stage_finalize;
+ object_class->get_property = gedit_theatrics_stage_get_property;
+ object_class->set_property = gedit_theatrics_stage_set_property;
+
+ g_object_class_install_property (object_class, PROP_ACTOR_DURATION,
+ g_param_spec_uint ("actor-duration",
+ "Actor Duration",
+ "The actor duration",
+ 0,
+ G_MAXUINT,
+ DEFAULT_DURATION,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+
+ signals[ACTOR_STEP] =
+ g_signal_new ("actor-step",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GeditTheatricsStageClass, actor_step),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1,
+ GEDIT_TYPE_THEATRICS_ACTOR);
+
+ signals[ITERATION] =
+ g_signal_new ("iteration",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GeditTheatricsStageClass, iteration),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+ g_type_class_add_private (object_class, sizeof (GeditTheatricsStagePrivate));
+}
+
+static void
+gedit_theatrics_stage_init (GeditTheatricsStage *stage)
+{
+ stage->priv = GEDIT_THEATRICS_STAGE_GET_PRIVATE (stage);
+
+ stage->priv->update_frequency = DEFAULT_UPDATE_FREQUENCY;
+ stage->priv->actor_duration = DEFAULT_DURATION;
+ stage->priv->playing = TRUE;
+
+ stage->priv->actors = g_hash_table_new (g_direct_hash,
+ g_direct_equal);
+}
+
+static void
+iterate_actors (gpointer key,
+ gpointer value,
+ GeditTheatricsStage *stage)
+{
+ GeditTheatricsActor *actor = GEDIT_THEATRICS_ACTOR (value);
+
+ gedit_theatrics_actor_step (actor);
+
+ g_signal_emit (G_OBJECT (stage), signals[ACTOR_STEP], 0, actor);
+
+ if (gedit_theatrics_actor_get_expired (actor))
+ {
+ g_hash_table_remove (stage->priv->actors, key);
+ }
+}
+
+static gboolean
+on_timeout (GeditTheatricsStage *stage)
+{
+ if (!stage->priv->playing || g_hash_table_size (stage->priv->actors) == 0)
+ {
+ stage->priv->timeout_id = 0;
+ return FALSE;
+ }
+
+ g_hash_table_foreach (stage->priv->actors,
+ (GHFunc)iterate_actors,
+ stage);
+
+ g_signal_emit (G_OBJECT (stage), signals[ITERATION], 0);
+
+ return TRUE;
+}
+
+static void
+check_timeout (GeditTheatricsStage *stage)
+{
+ if ((!stage->priv->playing ||
+ g_hash_table_size (stage->priv->actors) == 0) &&
+ stage->priv->timeout_id)
+ {
+ g_source_remove (stage->priv->timeout_id);
+ stage->priv->timeout_id = 0;
+ }
+ else if ((stage->priv->playing &&
+ g_hash_table_size (stage->priv->actors) > 0) &&
+ stage->priv->timeout_id <= 0)
+ {
+ stage->priv->timeout_id = g_timeout_add (stage->priv->update_frequency,
+ (GSourceFunc) on_timeout,
+ stage);
+ }
+}
+
+GeditTheatricsStage *
+gedit_theatrics_stage_new ()
+{
+ return g_object_new (GEDIT_TYPE_THEATRICS_STAGE, NULL);
+}
+
+GeditTheatricsStage *
+gedit_theatrics_stage_new_with_duration (guint actor_duration)
+{
+ return g_object_new (GEDIT_TYPE_THEATRICS_STAGE,
+ "actor-duration", actor_duration,
+ NULL);
+}
+
+GeditTheatricsActor *
+gedit_theatrics_stage_add (GeditTheatricsStage *stage,
+ GObject *target)
+{
+ g_return_val_if_fail (GEDIT_IS_THEATRICS_STAGE (stage), NULL);
+
+ return gedit_theatrics_stage_add_with_duration (stage, target,
+ stage->priv->actor_duration);
+}
+
+GeditTheatricsActor *
+gedit_theatrics_stage_add_with_duration (GeditTheatricsStage *stage,
+ GObject *target,
+ guint duration)
+{
+ GeditTheatricsActor *actor;
+
+ g_return_val_if_fail (GEDIT_IS_THEATRICS_STAGE (stage), NULL);
+
+ actor = g_hash_table_lookup (stage->priv->actors,
+ target);
+
+ if (actor != NULL)
+ {
+ g_warning ("Stage already contains this actor");
+ return NULL;
+ }
+
+ actor = gedit_theatrics_actor_new (target, duration);
+
+ g_hash_table_insert (stage->priv->actors,
+ target, actor);
+
+ check_timeout (stage);
+
+ return actor;
+}
+
+void
+gedit_theatrics_stage_remove (GeditTheatricsStage *stage,
+ GObject *target)
+{
+ g_return_if_fail (GEDIT_IS_THEATRICS_STAGE (stage));
+
+ g_hash_table_remove (stage->priv->actors, target);
+}
+
+void
+gedit_theatrics_stage_set_playing (GeditTheatricsStage *stage,
+ gboolean playing)
+{
+ g_return_if_fail (GEDIT_IS_THEATRICS_STAGE (stage));
+
+ stage->priv->playing = playing;
+}
+
+gboolean
+gedit_theatrics_stage_get_playing (GeditTheatricsStage *stage)
+{
+ g_return_val_if_fail (GEDIT_IS_THEATRICS_STAGE (stage), FALSE);
+
+ return stage->priv->playing;
+}
+
+/* ex:ts=8:noet: */
diff --git a/gedit/theatrics/gedit-theatrics-stage.h b/gedit/theatrics/gedit-theatrics-stage.h
new file mode 100644
index 0000000..ed31759
--- /dev/null
+++ b/gedit/theatrics/gedit-theatrics-stage.h
@@ -0,0 +1,87 @@
+/*
+ * gedit-theatrics-stage.h
+ * This file is part of gedit
+ *
+ * Copyright (C) 2010 - Ignacio Casal Quinteiro
+ *
+ * Based on Aaron Bockover <abockover novell com> work.
+ *
+ * gedit is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * gedit 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 gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifndef __GEDIT_THEATRICS_STAGE_H__
+#define __GEDIT_THEATRICS_STAGE_H__
+
+#include <glib-object.h>
+#include "gedit-theatrics-actor.h"
+
+G_BEGIN_DECLS
+
+#define GEDIT_TYPE_THEATRICS_STAGE (gedit_theatrics_stage_get_type ())
+#define GEDIT_THEATRICS_STAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_THEATRICS_STAGE, GeditTheatricsStage))
+#define GEDIT_THEATRICS_STAGE_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_THEATRICS_STAGE, GeditTheatricsStage const))
+#define GEDIT_THEATRICS_STAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GEDIT_TYPE_THEATRICS_STAGE, GeditTheatricsStageClass))
+#define GEDIT_IS_THEATRICS_STAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEDIT_TYPE_THEATRICS_STAGE))
+#define GEDIT_IS_THEATRICS_STAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEDIT_TYPE_THEATRICS_STAGE))
+#define GEDIT_THEATRICS_STAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GEDIT_TYPE_THEATRICS_STAGE, GeditTheatricsStageClass))
+
+typedef struct _GeditTheatricsStage GeditTheatricsStage;
+typedef struct _GeditTheatricsStageClass GeditTheatricsStageClass;
+typedef struct _GeditTheatricsStagePrivate GeditTheatricsStagePrivate;
+
+struct _GeditTheatricsStage
+{
+ GObject parent;
+
+ GeditTheatricsStagePrivate *priv;
+};
+
+struct _GeditTheatricsStageClass
+{
+ GObjectClass parent_class;
+
+ void (* actor_step) (GeditTheatricsStage *stage,
+ GeditTheatricsActor *actor);
+
+ void (* iteration) (GeditTheatricsStage *stage);
+};
+
+GType gedit_theatrics_stage_get_type (void) G_GNUC_CONST;
+
+GeditTheatricsStage *gedit_theatrics_stage_new (void);
+
+GeditTheatricsStage *gedit_theatrics_stage_new_with_duration(guint actor_duration);
+
+GeditTheatricsActor *gedit_theatrics_stage_add (GeditTheatricsStage *stage,
+ GObject *target);
+
+GeditTheatricsActor *gedit_theatrics_stage_add_with_duration(GeditTheatricsStage *stage,
+ GObject *target,
+ guint duration);
+
+void gedit_theatrics_stage_remove (GeditTheatricsStage *stage,
+ GObject *target);
+
+void gedit_theatrics_stage_set_playing (GeditTheatricsStage *stage,
+ gboolean playing);
+
+gboolean gedit_theatrics_stage_get_playing (GeditTheatricsStage *stage);
+
+G_END_DECLS
+
+#endif /* __GEDIT_THEATRICS_STAGE_H__ */
+
+/* ex:ts=8:noet: */
diff --git a/gedit/theatrics/gedit-theatrics-utils.c b/gedit/theatrics/gedit-theatrics-utils.c
new file mode 100644
index 0000000..374b7d2
--- /dev/null
+++ b/gedit/theatrics/gedit-theatrics-utils.c
@@ -0,0 +1,131 @@
+/*
+ * gedit-theatrics-utils.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 2010 - Ignacio Casal Quinteiro
+ *
+ * Based on Mike Krüger <mkrueger novell com> work.
+ *
+ * gedit is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * gedit 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 gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "gedit-theatrics-utils.h"
+
+void
+gedit_theatrics_utils_draw_round_rectangle (cairo_t *cr,
+ gboolean top_left_round,
+ gboolean top_right_round,
+ gboolean bottom_left_round,
+ gboolean bottom_right_round,
+ gdouble x,
+ gdouble y,
+ gdouble r,
+ gdouble w,
+ gdouble h)
+{
+ /*
+ UA****BQ
+ H C
+ * *
+ G D
+ TF****ES
+ */
+
+ cairo_new_path (cr);
+
+ if (top_left_round)
+ {
+ /* Move to A */
+ cairo_move_to (cr, x + r, y);
+ }
+ else
+ {
+ /* Move to U */
+ cairo_move_to (cr, x, y);
+ }
+
+ if (top_right_round)
+ {
+ /* Straight line to B */
+ cairo_line_to (cr, x + w - r, y);
+
+ /* Curve to C, Control points are both at Q */
+ cairo_curve_to (cr, x + w, y,
+ x + w, y,
+ x + w, y + r);
+ }
+ else
+ {
+ /* Straight line to Q */
+ cairo_line_to (cr, x + w, y);
+ }
+
+ if (bottom_right_round)
+ {
+ /* Move to D */
+ cairo_line_to (cr, x + w, y + h - r);
+
+ /* Curve to E */
+ cairo_curve_to (cr, x + w, y + h,
+ x + w, y + h,
+ x + w - r, y + h);
+ }
+ else
+ {
+ /* Move to S */
+ cairo_line_to (cr, x + w, y + h);
+ }
+
+ if (bottom_left_round)
+ {
+ /* Line to F */
+ cairo_line_to (cr, x + r, y + h);
+
+ /* Curve to G */
+ cairo_curve_to (cr, x, y + h,
+ x, y + h ,
+ x, y + h - r);
+ }
+ else
+ {
+ /* Line to T */
+ cairo_line_to (cr, x, y + h);
+ }
+
+ if (top_left_round)
+ {
+ /* Line to H */
+ cairo_line_to (cr, x, y + r);
+
+ /* Curve to A */
+ cairo_curve_to (cr, x, y,
+ x , y,
+ x + r, y);
+ }
+ else
+ {
+ /* Line to U */
+ cairo_line_to (cr, x, y);
+ }
+
+ cairo_close_path (cr);
+}
+
+/* ex:ts=8:noet: */
diff --git a/gedit/theatrics/gedit-theatrics-utils.h b/gedit/theatrics/gedit-theatrics-utils.h
new file mode 100644
index 0000000..8113c4b
--- /dev/null
+++ b/gedit/theatrics/gedit-theatrics-utils.h
@@ -0,0 +1,48 @@
+/*
+ * gedit-theatrics-utils.h
+ * This file is part of gedit
+ *
+ * Copyright (C) 2010 - Ignacio Casal Quinteiro
+ *
+ * Based on Mike Krüger <mkrueger novell com> work.
+ *
+ * gedit is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * gedit 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 gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifndef __GEDIT_THEATRICS_UTILS_H__
+#define __GEDIT_THEATRICS_UTILS_H__
+
+#include <glib.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+void gedit_theatrics_utils_draw_round_rectangle (cairo_t *cr,
+ gboolean top_left_round,
+ gboolean top_right_round,
+ gboolean bottom_left_round,
+ gboolean bottom_right_round,
+ gdouble x,
+ gdouble y,
+ gdouble r,
+ gdouble w,
+ gdouble h);
+
+G_END_DECLS
+
+#endif /* __GEDIT_THEATRICS_UTILS_H__ */
+
+/* ex:ts=8:noet: */
diff --git a/tests/Makefile.am b/tests/Makefile.am
index e4cd496..15fd334 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -23,6 +23,14 @@ TEST_PROGS += document-saver
document_saver_SOURCES = document-saver.c
document_saver_LDADD = $(progs_ldadd)
+TEST_PROGS += test-rounded-frame
+test_rounded_frame_SOURCES = test-rounded-frame.c
+test_rounded_frame_LDADD = $(progs_ldadd)
+
+TEST_PROGS += test-overlay
+test_overlay_SOURCES = test-overlay.c
+test_overlay_LDADD = $(progs_ldadd)
+
TESTS = $(TEST_PROGS)
EXTRA_DIST = setup-document-saver.sh
diff --git a/tests/test-overlay.c b/tests/test-overlay.c
new file mode 100644
index 0000000..4288473
--- /dev/null
+++ b/tests/test-overlay.c
@@ -0,0 +1,62 @@
+#include <gtk/gtk.h>
+#include <glib.h>
+#include "gedit-overlay.h"
+#include "gedit-rounded-frame.h"
+
+static void
+on_button_clicked (GtkWidget *button,
+ GtkWidget *frame)
+{
+ gtk_widget_destroy (frame);
+}
+
+gint
+main ()
+{
+ GtkWidget *window;
+ GtkWidget *textview;
+ GtkWidget *overlay;
+ GtkWidget *frame;
+ GtkWidget *entry;
+ GtkWidget *vbox;
+ GtkWidget *button;
+
+ gtk_init (NULL, NULL);
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_default_size (GTK_WINDOW (window), 300, 200);
+ vbox = gtk_vbox_new (FALSE, 0);
+ gtk_container_add (GTK_CONTAINER (window), vbox);
+
+ textview = gtk_text_view_new ();
+ overlay = gedit_overlay_new (textview);
+
+ gtk_box_pack_start (GTK_BOX (vbox), overlay, TRUE, TRUE, 0);
+
+ frame = gedit_rounded_frame_new ();
+ gtk_widget_show (frame);
+
+ entry = gtk_entry_new ();
+
+ gtk_container_add (GTK_CONTAINER (frame), entry);
+
+ gedit_overlay_add_animated_widget (GEDIT_OVERLAY (overlay),
+ frame,
+ 1000,
+ GEDIT_THEATRICS_CHOREOGRAPHER_EASING_EXPONENTIAL_IN_OUT,
+ GEDIT_THEATRICS_CHOREOGRAPHER_BLOCKING_DOWNSTAGE,
+ GTK_ORIENTATION_VERTICAL,
+ 0, 0);
+
+ button = gtk_button_new_with_label ("Hide");
+ gtk_box_pack_end (GTK_BOX (vbox), button, FALSE, FALSE, 0);
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (on_button_clicked),
+ frame);
+
+ gtk_widget_show_all (window);
+
+ gtk_main ();
+
+ return 0;
+}
diff --git a/tests/test-rounded-frame.c b/tests/test-rounded-frame.c
new file mode 100644
index 0000000..c0bdab9
--- /dev/null
+++ b/tests/test-rounded-frame.c
@@ -0,0 +1,29 @@
+#include <gtk/gtk.h>
+#include <glib.h>
+#include "gedit-rounded-frame.h"
+
+gint main ()
+{
+ GtkWidget *window;
+ GtkWidget *frame;
+ GtkWidget *entry;
+
+ gtk_init (NULL, NULL);
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+ frame = gedit_rounded_frame_new ();
+
+ gtk_container_add (GTK_CONTAINER (window), frame);
+
+ entry = gtk_entry_new ();
+
+ gtk_container_add (GTK_CONTAINER (frame), entry);
+ gtk_container_set_border_width (GTK_CONTAINER (frame), 10);
+
+ gtk_widget_show_all (window);
+
+ gtk_main ();
+
+ return 0;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]