[evolution/webkit-composer: 30/210] Make inserting a auto-replacing emoticons work
- From: Matthew Barnes <mbarnes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution/webkit-composer: 30/210] Make inserting a auto-replacing emoticons work
- Date: Mon, 8 Jul 2013 00:48:23 +0000 (UTC)
commit e6be3315dc5abb41d00eec40d615537faf84654d
Author: Dan Vrátil <dvratil redhat com>
Date: Thu Aug 9 10:28:59 2012 +0200
Make inserting a auto-replacing emoticons work
The algorithm for magic smileys is taken from GtkHTML
(I admit I don't 100% understand how it works), because
it's quick and known to work quite well.
TODO: It would be nice to automagically replace emoticons
in pasted and inserted text as well.
e-util/e-editor-actions.c | 46 +++-------
e-util/e-editor-widget.c | 175 +++++++++++++++++++++++++++++++++++++-
e-util/e-emoticon-chooser-menu.c | 2 +-
e-util/e-emoticon-chooser.c | 2 +-
e-util/e-emoticon-chooser.h | 4 +-
e-util/e-emoticon-tool-button.c | 2 +-
e-util/e-emoticon.c | 25 ++++++
e-util/e-emoticon.h | 2 +
8 files changed, 219 insertions(+), 39 deletions(-)
---
diff --git a/e-util/e-editor-actions.c b/e-util/e-editor-actions.c
index 0e6fdee..c09c63d 100644
--- a/e-util/e-editor-actions.c
+++ b/e-util/e-editor-actions.c
@@ -30,6 +30,7 @@
#include "e-editor-private.h"
#include "e-editor-widgets.h"
#include "e-emoticon-action.h"
+#include "e-emoticon-chooser.h"
#include "e-image-chooser-dialog.h"
static void
@@ -569,45 +570,24 @@ action_indent_cb (GtkAction *action,
static void
action_insert_emoticon_cb (GtkAction *action,
- EEditor *editor)
+ EEditor *editor)
{
- /* FIXME WEBKIT
- GtkHTML *html;
- HTMLObject *image;
- GtkIconInfo *icon_info;
- GtkIconTheme *icon_theme;
- GtkhtmlFaceChooser *chooser;
- GtkhtmlFace *face;
- const gchar *filename;
+ EEditorWidget *widget;
+ EEditorSelection *selection;
+ EEmoticonChooser *chooser;
+ EEmoticon *emoticon;
gchar *uri = NULL;
- html = gtkhtml_editor_get_html (editor);
+ chooser = E_EMOTICON_CHOOSER (action);
+ emoticon = e_emoticon_chooser_get_current_emoticon (chooser);
+ g_return_if_fail (emoticon != NULL);
- chooser = GTKHTML_FACE_CHOOSER (action);
- face = gtkhtml_face_chooser_get_current_face (chooser);
- g_return_if_fail (face != NULL);
-
- icon_theme = gtk_icon_theme_get_default ();
- icon_info = gtk_icon_theme_lookup_icon (
- icon_theme, face->icon_name, 16, 0);
- g_return_if_fail (icon_info != NULL);
-
- filename = gtk_icon_info_get_filename (icon_info);
- if (filename != NULL)
- uri = g_filename_to_uri (filename, NULL, NULL);
- gtk_icon_info_free (icon_info);
- g_return_if_fail (uri != NULL);
-
- image = html_image_new (
- html_engine_get_image_factory (html->engine),
- uri, NULL, NULL, -1, -1, FALSE, FALSE, 0, NULL,
- HTML_VALIGN_MIDDLE, FALSE);
- html_image_set_alt (HTML_IMAGE (image), face->text_face);
- html_engine_paste_object (
- html->engine, image, html_object_get_length (image));
+ uri = e_emoticon_get_uri (emoticon);
+ widget = e_editor_get_editor_widget (editor);
+ selection = e_editor_widget_get_selection (widget);
+ e_editor_selection_insert_image (selection, uri);
g_free (uri);
- */
}
static void
diff --git a/e-util/e-editor-widget.c b/e-util/e-editor-widget.c
index 4b55200..f5fed8c 100644
--- a/e-util/e-editor-widget.c
+++ b/e-util/e-editor-widget.c
@@ -22,8 +22,10 @@
#include "e-editor-widget.h"
#include "e-editor.h"
+#include "e-emoticon-chooser.h"
#include <glib/gi18n-lib.h>
+#include <gdk/gdkkeysyms.h>
struct _EEditorWidgetPrivate {
gint changed : 1;
@@ -47,8 +49,7 @@ struct _EEditorWidgetPrivate {
G_DEFINE_TYPE (
EEditorWidget,
e_editor_widget,
- WEBKIT_TYPE_WEB_VIEW
-);
+ WEBKIT_TYPE_WEB_VIEW);
enum {
PROP_0,
@@ -65,6 +66,24 @@ enum {
PROP_CAN_UNDO
};
+static WebKitDOMRange *
+editor_widget_get_dom_range (EEditorWidget *widget)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMDOMWindow *window;
+ WebKitDOMDOMSelection *selection;
+
+ document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (widget));
+ window = webkit_dom_document_get_default_view (document);
+ selection = webkit_dom_dom_window_get_selection (window);
+
+ if (webkit_dom_dom_selection_get_range_count (selection) < 1) {
+ return NULL;
+ }
+
+ return webkit_dom_dom_selection_get_range_at (selection, 0, NULL);
+}
+
static void
editor_widget_strip_formatting (EEditorWidget *widget)
{
@@ -129,6 +148,154 @@ editor_widget_selection_changed_cb (EEditorWidget *widget,
}
}
+/* Based on original use_pictograms() from GtkHTML */
+static const gchar *emoticons_chars =
+ /* 0 */ "DO)(|/PQ*!"
+ /* 10 */ "S\0:-\0:\0:-\0"
+ /* 20 */ ":\0:;=-\"\0:;"
+ /* 30 */ "B\"|\0:-'\0:X"
+ /* 40 */ "\0:\0:-\0:\0:-"
+ /* 50 */ "\0:\0:-\0:\0:-"
+ /* 60 */ "\0:\0:\0:-\0:\0"
+ /* 70 */ ":-\0:\0:-\0:\0";
+static gint emoticons_states[] = {
+ /* 0 */ 12, 17, 22, 34, 43, 48, 53, 58, 65, 70,
+ /* 10 */ 75, 0, -15, 15, 0, -15, 0, -17, 20, 0,
+ /* 20 */ -17, 0, -14, -20, -14, 28, 63, 0, -14, -20,
+ /* 30 */ -3, 63, -18, 0, -12, 38, 41, 0, -12, -2,
+ /* 40 */ 0, -4, 0, -10, 46, 0, -10, 0, -19, 51,
+ /* 50 */ 0, -19, 0, -11, 56, 0, -11, 0, -13, 61,
+ /* 60 */ 0, -13, 0, -6, 0, 68, -7, 0, -7, 0,
+ /* 70 */ -16, 73, 0, -16, 0, -21, 78, 0, -21, 0 };
+static const gchar *emoticons_icon_names[] = {
+ "face-angel",
+ "face-angry",
+ "face-cool",
+ "face-crying",
+ "face-devilish",
+ "face-embarrassed",
+ "face-kiss",
+ "face-laugh", /* not used */
+ "face-monkey", /* not used */
+ "face-plain",
+ "face-raspberry",
+ "face-sad",
+ "face-sick",
+ "face-smile",
+ "face-smile-big",
+ "face-smirk",
+ "face-surprise",
+ "face-tired",
+ "face-uncertain",
+ "face-wink",
+ "face-worried"
+};
+
+static void
+editor_widget_check_magic_smileys (EEditorWidget *widget,
+ WebKitDOMRange *range)
+{
+ gint pos;
+ gint state;
+ gint relative;
+ gint start;
+ gchar *node_text;
+ gunichar uc;
+ WebKitDOMNode *node;
+
+ node = webkit_dom_range_get_end_container (range, NULL);
+ if (!webkit_dom_node_get_node_type (node) == 3) {
+ return;
+ }
+
+ node_text = webkit_dom_text_get_whole_text ((WebKitDOMText *) node);
+ start = webkit_dom_range_get_end_offset (range, NULL) - 1;
+ pos = start;
+ state = 0;
+ while (pos >= 0) {
+ uc = g_utf8_get_char (g_utf8_offset_to_pointer (node_text, pos));
+ relative = 0;
+ while (emoticons_chars[state + relative]) {
+ if (emoticons_chars[state + relative] == uc)
+ break;
+ relative++;
+ }
+ state = emoticons_states[state + relative];
+ /* 0 .. not found, -n .. found n-th */
+ if (state <= 0)
+ break;
+ pos--;
+ }
+
+ /* Special case needed to recognize angel and devilish. */
+ if (pos > 0 && state == -14) {
+ uc = g_utf8_get_char (g_utf8_offset_to_pointer (node_text, pos - 1));
+ if (uc == 'O') {
+ state = -1;
+ pos--;
+ } else if (uc == '>') {
+ state = -5;
+ pos--;
+ }
+ }
+
+ if (state < 0) {
+ GtkIconInfo *icon_info;
+ const gchar *filename;
+ gchar *filename_uri;
+ WebKitDOMDocument *document;
+ WebKitDOMDOMWindow *window;
+ WebKitDOMDOMSelection *selection;
+
+ if (pos > 0) {
+ uc = g_utf8_get_char (g_utf8_offset_to_pointer (node_text, pos - 1));
+ if (uc != ' ' && uc != '\t')
+ return;
+ }
+
+ /* Select the text-smiley and replace it by <img> */
+ document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (widget));
+ window = webkit_dom_document_get_default_view (document);
+ selection = webkit_dom_dom_window_get_selection (window);
+ webkit_dom_dom_selection_set_base_and_extent (
+ selection, webkit_dom_range_get_end_container (range, NULL),
+ pos, webkit_dom_range_get_end_container (range, NULL),
+ start + 1, NULL);
+
+ /* Convert a named icon to a file URI. */
+ icon_info = gtk_icon_theme_lookup_icon (
+ gtk_icon_theme_get_default (),
+ emoticons_icon_names[-state - 1], 16, 0);
+ g_return_if_fail (icon_info != NULL);
+ filename = gtk_icon_info_get_filename (icon_info);
+ g_return_if_fail (filename != NULL);
+ filename_uri = g_filename_to_uri (filename, NULL, NULL);
+
+ e_editor_selection_insert_image (
+ widget->priv->selection, filename_uri);
+
+ g_free (filename_uri);
+ gtk_icon_info_free (icon_info);
+ }
+}
+
+static gboolean
+editor_widget_key_release_event (GtkWidget *gtk_widget,
+ GdkEventKey *event)
+{
+ WebKitDOMRange *range;
+ EEditorWidget *widget = E_EDITOR_WIDGET (gtk_widget);
+
+ range = editor_widget_get_dom_range (widget);
+
+ if (widget->priv->magic_smileys) {
+ editor_widget_check_magic_smileys (widget, range);
+ }
+
+ /* Propagate the event to WebKit */
+ return FALSE;
+}
+
static void
e_editor_widget_get_property (GObject *object,
guint property_id,
@@ -251,6 +418,7 @@ static void
e_editor_widget_class_init (EEditorWidgetClass *klass)
{
GObjectClass *object_class;
+ GtkWidgetClass *widget_class;
g_type_class_add_private (klass, sizeof (EEditorWidgetPrivate));
@@ -259,6 +427,9 @@ e_editor_widget_class_init (EEditorWidgetClass *klass)
object_class->set_property = e_editor_widget_set_property;
object_class->finalize = e_editor_widget_finalize;
+ widget_class = GTK_WIDGET_CLASS (klass);
+ widget_class->key_release_event = editor_widget_key_release_event;
+
g_object_class_install_property (
object_class,
PROP_MODE,
diff --git a/e-util/e-emoticon-chooser-menu.c b/e-util/e-emoticon-chooser-menu.c
index 619bd21..7bf6184 100644
--- a/e-util/e-emoticon-chooser-menu.c
+++ b/e-util/e-emoticon-chooser-menu.c
@@ -133,7 +133,7 @@ emoticon_chooser_menu_init (EEmoticonChooserMenu *chooser_menu)
GList *list, *iter;
chooser = E_EMOTICON_CHOOSER (chooser_menu);
- list = e_emoticon_chooser_get_items (chooser);
+ list = e_emoticon_chooser_get_items ();
for (iter = list; iter != NULL; iter = iter->next) {
EEmoticon *face = iter->data;
diff --git a/e-util/e-emoticon-chooser.c b/e-util/e-emoticon-chooser.c
index c8a92b0..8136f2c 100644
--- a/e-util/e-emoticon-chooser.c
+++ b/e-util/e-emoticon-chooser.c
@@ -168,7 +168,7 @@ e_emoticon_chooser_item_activated (EEmoticonChooser *chooser)
}
GList *
-e_emoticon_chooser_get_items (EEmoticonChooser *chooser)
+e_emoticon_chooser_get_items (void)
{
GList *list = NULL;
gint ii;
diff --git a/e-util/e-emoticon-chooser.h b/e-util/e-emoticon-chooser.h
index 7390da3..a134c7e 100644
--- a/e-util/e-emoticon-chooser.h
+++ b/e-util/e-emoticon-chooser.h
@@ -55,6 +55,7 @@ struct _EEmoticonChooserIface {
};
GType e_emoticon_chooser_get_type (void);
+
EEmoticon * e_emoticon_chooser_get_current_emoticon
(EEmoticonChooser *chooser);
void e_emoticon_chooser_set_current_emoticon
@@ -62,7 +63,8 @@ void e_emoticon_chooser_set_current_emoticon
EEmoticon *emoticon);
void e_emoticon_chooser_item_activated
(EEmoticonChooser *chooser);
-GList * e_emoticon_chooser_get_items (EEmoticonChooser *chooser);
+
+GList * e_emoticon_chooser_get_items (void);
G_END_DECLS
diff --git a/e-util/e-emoticon-tool-button.c b/e-util/e-emoticon-tool-button.c
index dc0d0dd..eaf2105 100644
--- a/e-util/e-emoticon-tool-button.c
+++ b/e-util/e-emoticon-tool-button.c
@@ -601,7 +601,7 @@ emoticon_tool_button_init (EEmoticonToolButton *button)
container = widget;
chooser = E_EMOTICON_CHOOSER (button);
- list = e_emoticon_chooser_get_items (chooser);
+ list = e_emoticon_chooser_get_items ();
g_assert (g_list_length (list) <= NUM_ROWS * NUM_COLS);
for (iter = list, ii = 0; iter != NULL; iter = iter->next, ii++) {
diff --git a/e-util/e-emoticon.c b/e-util/e-emoticon.c
index 1d394e6..d5b69c6 100644
--- a/e-util/e-emoticon.c
+++ b/e-util/e-emoticon.c
@@ -17,6 +17,8 @@
#include "e-emoticon.h"
+#include <gtk/gtk.h>
+
static EEmoticon *
emoticon_copy (EEmoticon *emoticon)
{
@@ -87,3 +89,26 @@ e_emoticon_free (EEmoticon *emoticon)
{
g_boxed_free (E_TYPE_EMOTICON, emoticon);
}
+
+gchar *
+e_emoticon_get_uri(EEmoticon *emoticon)
+{
+ GtkIconInfo *icon_info;
+ GtkIconTheme *icon_theme;
+ const gchar *filename;
+ gchar *uri = NULL;
+
+ icon_theme = gtk_icon_theme_get_default ();
+ icon_info = gtk_icon_theme_lookup_icon (
+ icon_theme, emoticon->icon_name, 16, 0);
+ g_return_val_if_fail (icon_info != NULL, NULL);
+
+ filename = gtk_icon_info_get_filename (icon_info);
+ if (filename != NULL) {
+ uri = g_filename_to_uri (filename, NULL, NULL);
+ }
+ gtk_icon_info_free (icon_info);
+ g_return_val_if_fail (uri != NULL, NULL);
+
+ return uri;
+}
diff --git a/e-util/e-emoticon.h b/e-util/e-emoticon.h
index cf270ef..17995d5 100644
--- a/e-util/e-emoticon.h
+++ b/e-util/e-emoticon.h
@@ -43,6 +43,8 @@ gboolean e_emoticon_equal (EEmoticon *emoticon_a,
EEmoticon * e_emoticon_copy (EEmoticon *emoticon);
void e_emoticon_free (EEmoticon *emoticon);
+gchar * e_emoticon_get_uri (EEmoticon *emoticon);
+
G_END_DECLS
#endif /* E_EMOTICON_H */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]