[gnome-characters/wip/dueno/local-scripts] categoryList: Add "Local scripts" tab
- From: Daiki Ueno <dueno src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-characters/wip/dueno/local-scripts] categoryList: Add "Local scripts" tab
- Date: Mon, 15 Jun 2015 07:06:14 +0000 (UTC)
commit b23dec0523fbab8515663c56128c5f8b8794ef72
Author: Daiki Ueno <dueno src gnome org>
Date: Mon Jun 15 15:19:23 2015 +0900
categoryList: Add "Local scripts" tab
https://bugzilla.gnome.org/show_bug.cgi?id=743643
data/org.gnome.Characters.gschema.xml | 12 ++++
lib/gc.c | 96 +++++++++++++++++++++++++++++---
lib/gc.h | 5 ++
src/categoryList.js | 42 ++++++++++++++-
src/characterList.js | 16 ++++++
src/window.js | 3 +
6 files changed, 163 insertions(+), 11 deletions(-)
---
diff --git a/data/org.gnome.Characters.gschema.xml b/data/org.gnome.Characters.gschema.xml
index 30fb382..09ae962 100644
--- a/data/org.gnome.Characters.gschema.xml
+++ b/data/org.gnome.Characters.gschema.xml
@@ -14,5 +14,17 @@
<default>100</default>
<summary>Maximum recent characters</summary>
</key>
+ <key name="scripts" type="as">
+ <!-- TRANSLATORS: list Unicode scripts used in your language.
+ For Latin languages, keep it empty. -->
+ <default l10n="messages" context="scripts">[]</default>
+ <summary>A list of Unicode scripts used in this locale.</summary>
+ </key>
+ <key name="scripts-character" type="s">
+ <!-- TRANSLATORS: put the most representative character in your language.
+ This will be used as a label of the 'Local scripts' tab. -->
+ <default l10n="messages" context="scripts-character">'?'</default>
+ <summary>Character representing Unicode scripts used in this locale.</summary>
+ </key>
</schema>
</schemalist>
diff --git a/lib/gc.c b/lib/gc.c
index 83c7c8b..a1efec5 100644
--- a/lib/gc.c
+++ b/lib/gc.c
@@ -76,7 +76,7 @@ struct GcCharacterIter
size_t block_index;
size_t block_count;
- const uc_script_t *script;
+ const uc_script_t * const * scripts;
uc_general_category_t category;
const gchar * const * keywords;
@@ -199,20 +199,32 @@ gc_character_iter_init_for_blocks (GcCharacterIter *iter,
}
static gboolean
-filter_script (GcCharacterIter *iter, ucs4_t uc)
+filter_scripts (GcCharacterIter *iter, ucs4_t uc)
{
- return uc_is_print (uc) && uc_is_script (uc, iter->script);
+ const uc_script_t * const *scripts = iter->scripts;
+
+ if (!uc_is_print (uc))
+ return FALSE;
+
+ while (*scripts)
+ {
+ if (uc_is_script (uc, *scripts))
+ return TRUE;
+ scripts++;
+ }
+
+ return FALSE;
}
static void
-gc_character_iter_init_for_script (GcCharacterIter *iter,
- const uc_script_t *script)
+gc_character_iter_init_for_scripts (GcCharacterIter *iter,
+ const uc_script_t * const * scripts)
{
gc_character_iter_init (iter);
iter->blocks = all_blocks;
iter->block_count = all_block_count;
- iter->filter = filter_script;
- iter->script = script;
+ iter->filter = filter_scripts;
+ iter->scripts = scripts;
}
static void
@@ -327,8 +339,13 @@ gc_enumerate_character_by_category (GcCharacterIter *iter,
return;
case GC_CATEGORY_LATIN:
- gc_character_iter_init_for_script (iter, uc_script ('A'));
- return;
+ {
+ static const uc_script_t *latin_scripts[2];
+ latin_scripts[0] = uc_script ('A');
+ latin_scripts[1] = NULL;
+ gc_character_iter_init_for_scripts (iter, latin_scripts);
+ return;
+ }
case GC_CATEGORY_EMOTICON:
{
@@ -437,6 +454,7 @@ struct SearchData
{
GcCategory category;
gchar **keywords;
+ const uc_script_t **scripts;
gunichar uc;
gint max_matches;
};
@@ -446,6 +464,8 @@ search_data_free (struct SearchData *data)
{
if (data->keywords)
g_strfreev (data->keywords);
+ if (data->scripts)
+ g_free (data->scripts);
g_slice_free (struct SearchData, data);
}
@@ -558,6 +578,64 @@ gc_search_by_keywords (const gchar * const * keywords,
g_task_run_in_thread (task, gc_search_by_keywords_thread);
}
+static void
+gc_search_by_scripts_thread (GTask *task,
+ gpointer source_object,
+ gpointer task_data,
+ GCancellable *cancellable)
+{
+ GcCharacterIter iter;
+ GArray *result;
+ struct SearchData *data = task_data;
+
+ if (!all_blocks)
+ uc_all_blocks (&all_blocks, &all_block_count);
+
+ result = g_array_new (FALSE, FALSE, sizeof (gunichar));
+ gc_character_iter_init_for_scripts (&iter,
+ (const uc_script_t * const *) data->scripts);
+ while (!g_cancellable_is_cancelled (cancellable)
+ && gc_character_iter_next (&iter))
+ {
+ gunichar uc = gc_character_iter_get (&iter);
+ g_array_append_val (result, uc);
+ }
+
+ g_task_return_pointer (task, result, (GDestroyNotify) g_array_unref);
+}
+
+/**
+ * gc_search_by_scripts:
+ * @scripts: (array zero-terminated=1) (element-type utf8): an array of scripts
+ * @max_matches: the maximum number of results.
+ * @cancellable: a #GCancellable.
+ * @callback: a #GAsyncReadyCallback.
+ * @user_data: a user data passed to @callback.
+ */
+void
+gc_search_by_scripts (const gchar * const * scripts,
+ gint max_matches,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+ struct SearchData *data;
+ guint length, i;
+
+ task = g_task_new (NULL, cancellable, callback, user_data);
+
+ data = g_slice_new0 (struct SearchData);
+ length = g_strv_length ((gchar **) scripts);
+ data->scripts = g_malloc0_n (length + 1, sizeof (uc_script_t *));
+ for (i = 0; i < length; i++)
+ data->scripts[i] = uc_script_byname (scripts[i]);
+ data->max_matches = max_matches;
+ g_task_set_task_data (task, data,
+ (GDestroyNotify) search_data_free);
+ g_task_run_in_thread (task, gc_search_by_scripts_thread);
+}
+
static int
confusable_character_class_compare (const void *a,
const void *b)
diff --git a/lib/gc.h b/lib/gc.h
index a735e11..6383cdd 100644
--- a/lib/gc.h
+++ b/lib/gc.h
@@ -49,6 +49,11 @@ void gc_search_by_keywords (const gchar * const * keywords,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
+void gc_search_by_scripts (const gchar * const * scripts,
+ gint max_matches,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
void gc_search_related (gunichar uc,
gint max_matches,
GCancellable *cancellable,
diff --git a/src/categoryList.js b/src/categoryList.js
index 82beff7..c1f90cc 100644
--- a/src/categoryList.js
+++ b/src/categoryList.js
@@ -18,11 +18,15 @@
const Lang = imports.lang;
const Params = imports.params;
+const Cairo = imports.cairo;
+const PangoCairo = imports.gi.PangoCairo;
+const Pango = imports.gi.Pango;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk;
const Gettext = imports.gettext;
const Gc = imports.gi.Gc;
+const Main = imports.main;
const Category = [
{
@@ -78,6 +82,11 @@ const Category = [
category: Gc.Category.EMOTICON,
title: N_('Emoticons'),
icon_name: 'face-smile-symbolic'
+ },
+ {
+ name: 'local',
+ category: Gc.Category.NONE,
+ title: N_('Local scripts')
}
];
@@ -97,8 +106,13 @@ const CategoryListRowWidget = new Lang.Class({
margin_start: 10 });
this.add(hbox);
- let icon = new Gio.ThemedIcon({ name: category.icon_name });
- let image = Gtk.Image.new_from_gicon(icon, Gtk.IconSize.LARGE_TOOLBAR);
+ let image;
+ if (category.name == 'local') {
+ image = this._createScriptsImage();
+ } else {
+ let icon = new Gio.ThemedIcon({ name: category.icon_name });
+ image = Gtk.Image.new_from_gicon(icon, Gtk.IconSize.LARGE_TOOLBAR);
+ }
image.get_style_context().add_class('category-image');
hbox.pack_start(image, false, false, 2);
@@ -106,6 +120,25 @@ const CategoryListRowWidget = new Lang.Class({
halign: Gtk.Align.START });
label.get_style_context().add_class('category-label');
hbox.pack_start(label, true, true, 0);
+ },
+
+ _createScriptsImage: function() {
+ let surface = new Cairo.ImageSurface(Cairo.Format.ARGB32, 24, 24);
+ let cr = new CairoContext(surface);
+ let layout = PangoCairo.create_layout(cr);
+
+ let context = this.get_pango_context();
+ layout.get_context().set_font_map(context.get_font_map());
+ let fontDescription = context.get_font_description();
+ fontDescription.set_size(16 * Pango.SCALE);
+ layout.set_font_description(fontDescription);
+
+ let [uc, length] =
+ Main.settings.get_value('scripts-character').get_string();
+ layout.set_text(uc, length);
+ PangoCairo.show_layout(cr, layout);
+
+ return Gtk.Image.new_from_surface(surface);
}
});
@@ -120,8 +153,13 @@ const CategoryListWidget = new Lang.Class({
// Mimic GtkStackSidebar to take advantage of the standard theme.
this.get_style_context().add_class('sidebar');
+ let scripts = Main.settings.get_value('scripts').get_strv();
+ let scripts_visible = scripts.length > 0;
+
for (let index in Category) {
let category = Category[index];
+ if (category.name == 'local' && !scripts_visible)
+ continue;
let rowWidget = new CategoryListRowWidget({}, category);
// Mimic GtkStackSidebar to take advantage of the standard theme.
rowWidget.get_style_context().add_class('sidebar-item');
diff --git a/src/characterList.js b/src/characterList.js
index 4dbdf59..4d3ec08 100644
--- a/src/characterList.js
+++ b/src/characterList.js
@@ -376,6 +376,22 @@ const CharacterListView = new Lang.Class({
}));
},
+ searchByScripts: function(scripts) {
+ this._startSearch()
+ Gc.search_by_scripts(
+ scripts,
+ -1,
+ this._cancellable,
+ Lang.bind(this, function(source_object, res, user_data) {
+ try {
+ let result = Gc.search_finish(res);
+ this._finishSearch(result);
+ } catch (e) {
+ log("Failed to search by scripts: " + e);
+ }
+ }));
+ },
+
cancelSearch: function() {
this._cancellable.cancel();
this._finishSearch([]);
diff --git a/src/window.js b/src/window.js
index e3eea97..59f39e4 100644
--- a/src/window.js
+++ b/src/window.js
@@ -330,6 +330,9 @@ const MainView = new Lang.Class({
characterList.setCharacters(this.recentCharacters);
characterList.updateCharacterList();
}
+ } else if (name == 'local') {
+ let scripts = Main.settings.get_value('scripts').get_strv();
+ characterList.searchByScripts(scripts);
} else {
let category = null;
for (let index in CategoryList.Category) {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]