diff options
Diffstat (limited to 'ui/gtk3/emojier.vala')
-rw-r--r-- | ui/gtk3/emojier.vala | 991 |
1 files changed, 721 insertions, 270 deletions
diff --git a/ui/gtk3/emojier.vala b/ui/gtk3/emojier.vala index 0c0865f1..cd98c9d7 100644 --- a/ui/gtk3/emojier.vala +++ b/ui/gtk3/emojier.vala @@ -226,43 +226,6 @@ public class IBusEmojier : Gtk.ApplicationWindow { } } } - private class ETitleLabelBox : Gtk.HeaderBar { - private Gtk.Label m_lang_label; - private Gtk.Label m_title_label; - - public ETitleLabelBox(string title) { - GLib.Object( - name : "IBusEmojierTitleLabelBox", - show_close_button: true, - decoration_layout: ":close", - title: title - ); - var vbox = new Gtk.Box(Gtk.Orientation.VERTICAL, 0); - set_custom_title(vbox); - m_title_label = new Gtk.Label(title); - m_title_label.get_style_context().add_class(Gtk.STYLE_CLASS_TITLE); - vbox.pack_start(m_title_label, true, false, 0); - m_lang_label = new Gtk.Label(null); - m_lang_label.get_style_context().add_class( - Gtk.STYLE_CLASS_SUBTITLE); - vbox.pack_start(m_lang_label, true, false, 0); - - var menu = new GLib.Menu(); - menu.append(_("Show emoji variants"), "win.variant"); - var menu_button = new Gtk.MenuButton(); - menu_button.set_direction(Gtk.ArrowType.NONE); - menu_button.set_valign(Gtk.Align.CENTER); - menu_button.set_menu_model(menu); - menu_button.set_tooltip_text(_("Menu")); - pack_end(menu_button); - } - public new void set_title(string title) { - m_title_label.set_text(title); - } - public void set_lang_label(string str) { - m_lang_label.set_text(str); - } - } private class LoadProgressObject : GLib.Object { public LoadProgressObject() { } @@ -275,6 +238,8 @@ public class IBusEmojier : Gtk.ApplicationWindow { BACKWARD, } + public const uint BUTTON_CLOSE_BUTTON = 1000; + private const uint EMOJI_GRID_PAGE = 10; private const string EMOJI_CATEGORY_FAVORITES = N_("Favorites"); private const string EMOJI_CATEGORY_OTHERS = N_("Others"); @@ -313,11 +278,19 @@ public class IBusEmojier : Gtk.ApplicationWindow { private static bool m_show_unicode = false; private static LoadProgressObject m_unicode_progress_object; private static bool m_loaded_unicode = false; + private static string m_warning_message = ""; private ThemedRGBA m_rgba; private Gtk.Box m_vbox; - private ETitleLabelBox m_title; private EEntry m_entry; + /* If emojier is emoji category list or Unicode category list, + * m_annotation is "" and preedit is also "". + * If emojier is candidate mode, m_annotation is an annotation and + * get_current_candidate() returns the current emoji. + * But the current preedit can be "" in candidate mode in case that + * Unicode candidate window has U+0000. + */ + private string m_annotation = ""; private string? m_backward; private int m_backward_index = -1; private EScrolledWindow? m_scrolled_window = null; @@ -326,8 +299,20 @@ public class IBusEmojier : Gtk.ApplicationWindow { private string m_input_context_path = ""; private GLib.MainLoop? m_loop; private string? m_result; - private string? m_unicode_point = null; + /* If m_candidate_panel_is_visible is true, emojier is candidate mode and + * the emoji lookup window is visible. + * If m_candidate_panel_is_visible is false, the emoji lookup window is + * not visible but the mode is not clear. + */ private bool m_candidate_panel_is_visible; + /* If m_candidate_panel_mode is true, emojier is candidate mode and + * it does not depend on whether the window is visible or not. + * I.E. the first candidate does not show the lookup window and the + * second one shows the window. + * If m_candidate_panel_mode is false, emojier is emoji category list or + * Unicode category list. + */ + private bool m_candidate_panel_mode; private int m_category_active_index = -1; private IBus.LookupTable m_lookup_table; private Gtk.Label[] m_candidates; @@ -337,23 +322,18 @@ public class IBusEmojier : Gtk.ApplicationWindow { protected static double m_mouse_x; protected static double m_mouse_y; private Gtk.ProgressBar m_unicode_progress_bar; + private uint m_unicode_progress_id; private Gtk.Label m_unicode_percent_label; private double m_unicode_percent; + private Gdk.Rectangle m_cursor_location; + private bool m_is_up_side_down = false; + private uint m_redraw_window_id; public signal void candidate_clicked(uint index, uint button, uint state); public IBusEmojier() { GLib.Object( - type : Gtk.WindowType.TOPLEVEL, - events : Gdk.EventMask.KEY_PRESS_MASK | - Gdk.EventMask.KEY_RELEASE_MASK | - Gdk.EventMask.BUTTON_PRESS_MASK | - Gdk.EventMask.BUTTON_RELEASE_MASK, - window_position : Gtk.WindowPosition.CENTER, - icon_name: "ibus-setup", - accept_focus : true, - resizable : true, - focus_visible : true + type : Gtk.WindowType.POPUP ); // GLib.ActionEntry accepts const variables only. @@ -363,6 +343,9 @@ public class IBusEmojier : Gtk.ApplicationWindow { new GLib.Variant.boolean(m_show_emoji_variant)); action.activate.connect(check_action_variant_cb); add_action(action); + action = new GLib.SimpleAction("close", null); + action.activate.connect(action_close_cb); + add_action(action); if (m_current_lang_id == null) m_current_lang_id = "en"; if (m_emoji_font_family == null) @@ -448,14 +431,12 @@ public class IBusEmojier : Gtk.ApplicationWindow { css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); - m_title = new ETitleLabelBox(_("Emoji Choice")); - set_titlebar(m_title); m_vbox = new Gtk.Box(Gtk.Orientation.VERTICAL, 0); add(m_vbox); m_entry = new EEntry(); m_entry.set_placeholder_text(_("Type annotation or choose emoji")); - m_vbox.add(m_entry); + //m_vbox.add(m_entry); m_entry.changed.connect(() => { update_candidate_window(); }); @@ -480,10 +461,16 @@ public class IBusEmojier : Gtk.ApplicationWindow { m_loop.quit(); }); + size_allocate.connect((w, a) => { + adjust_window_position(); + }); + candidate_clicked.connect((i, b, s) => { - candidate_panel_select_index(i); + if (m_input_context_path != "") + candidate_panel_select_index(i, b); }); + if (m_annotation_to_emojis_dict == null) { reload_emoji_dict(); } @@ -814,6 +801,12 @@ public class IBusEmojier : Gtk.ApplicationWindow { private void remove_all_children() { + if (m_list_box != null) { + foreach (Gtk.Widget w in m_list_box.get_children()) { + w.destroy(); + } + m_list_box = null; + } foreach (Gtk.Widget w in m_vbox.get_children()) { if (w.name == "IBusEmojierEntry" || w.name == "IBusEmojierTitleLabelBox") { @@ -824,15 +817,40 @@ public class IBusEmojier : Gtk.ApplicationWindow { } + private void clamp_page() { + Gtk.ListBoxRow row; + if (m_category_active_index >= 0) { + row = m_list_box.get_row_at_index(m_category_active_index); + m_list_box.select_row(row); + } else { + row = m_list_box.get_row_at_index(0); + } + Gtk.Allocation alloc = { 0, 0, 0, 0 }; + row.get_allocation(out alloc); + var adjustment = m_scrolled_window.get_vadjustment(); + adjustment.clamp_page(alloc.y, alloc.y + alloc.height); + return_val_if_fail(m_category_active_index >= 0, false); + m_lookup_table.set_cursor_pos((uint)m_category_active_index); + } + + private void show_category_list() { + // Do not call remove_all_children() to work adjustment.clamp_page() + // with PageUp/Down. + // After show_candidate_panel() is called, m_category_active_index + // is saved for Escape key but m_list_box is null by + // remove_all_children(). + if (m_category_active_index >= 0 && m_list_box != null) { + var row = m_list_box.get_row_at_index(m_category_active_index); + m_list_box.select_row(row); + return; + } + if (m_category_active_index < 0) + m_category_active_index = 0; remove_all_children(); m_scrolled_window = new EScrolledWindow(); set_fixed_size(); - m_title.set_title(_("Emoji Choice")); - string language = - IBus.get_language_name(m_current_lang_id); - m_title.set_lang_label(language); m_vbox.add(m_scrolled_window); Gtk.Viewport viewport = new Gtk.Viewport(null, null); m_scrolled_window.add(viewport); @@ -842,53 +860,21 @@ public class IBusEmojier : Gtk.ApplicationWindow { Gtk.Adjustment adjustment = m_scrolled_window.get_vadjustment(); m_list_box.set_adjustment(adjustment); m_list_box.row_activated.connect((box, gtkrow) => { - m_category_active_index = -1; + m_category_active_index = gtkrow.get_index(); EBoxRow row = gtkrow as EBoxRow; show_emoji_for_category(row.text); + show_all(); }); - uint n = 0; - if (m_favorites.length > 0) { - EBoxRow row = new EBoxRow(EMOJI_CATEGORY_FAVORITES); - EPaddedLabelBox widget = - new EPaddedLabelBox(_(EMOJI_CATEGORY_FAVORITES), - Gtk.Align.CENTER); - row.add(widget); - m_list_box.add(row); - if (n++ == m_category_active_index) - m_list_box.select_row(row); - } - GLib.List<unowned string> categories = - m_category_to_emojis_dict.get_keys(); - // FIXME: How to cast GLib.CompareFunc<string> to strcmp? - categories.sort((a, b) => { - if (a == EMOJI_CATEGORY_OTHERS && b != EMOJI_CATEGORY_OTHERS) - return 1; - else if (a != EMOJI_CATEGORY_OTHERS && b == EMOJI_CATEGORY_OTHERS) - return -1; - return GLib.strcmp(_(a), _(b)); - }); - foreach (unowned string category in categories) { - // "Others" category includes next unicode chars and fonts do not support - // the base and varints yet. - if (category == EMOJI_CATEGORY_OTHERS) - continue; + uint ncandidates = m_lookup_table.get_number_of_candidates(); + for (uint i = 0; i < ncandidates; i++) { + string category = m_lookup_table.get_candidate(i).text; EBoxRow row = new EBoxRow(category); EPaddedLabelBox widget = new EPaddedLabelBox(_(category), Gtk.Align.CENTER); row.add(widget); m_list_box.add(row); - if (n++ == m_category_active_index) - m_list_box.select_row(row); - } - if (m_unicode_block_list.length() > 0) { - EBoxRow row = new EBoxRow(EMOJI_CATEGORY_UNICODE); - EPaddedLabelBox widget = - new EPaddedLabelBox(_(EMOJI_CATEGORY_UNICODE), - Gtk.Align.CENTER); - row.add(widget); - m_list_box.add(row); - if (n++ == m_category_active_index) + if (i == m_category_active_index) m_list_box.select_row(row); } @@ -903,6 +889,7 @@ public class IBusEmojier : Gtk.ApplicationWindow { private void show_emoji_for_category(string category) { if (category == EMOJI_CATEGORY_FAVORITES) { m_lookup_table.clear(); + m_candidate_panel_mode = true; foreach (unowned string favorate in m_favorites) { IBus.Text text = new IBus.Text.from_string(favorate); m_lookup_table.append_candidate(text); @@ -911,25 +898,26 @@ public class IBusEmojier : Gtk.ApplicationWindow { } else if (category == EMOJI_CATEGORY_UNICODE) { m_category_active_index = -1; m_show_unicode = true; - show_unicode_blocks(); + update_unicode_blocks(); return; } else { unowned GLib.SList<unowned string> emojis = m_category_to_emojis_dict.lookup(category); m_lookup_table.clear(); + m_candidate_panel_mode = true; foreach (unowned string emoji in emojis) { IBus.Text text = new IBus.Text.from_string(emoji); m_lookup_table.append_candidate(text); } m_backward = category; } + m_annotation = m_lookup_table.get_candidate(0).text; // Restore the cursor position before the special table of // emoji variants is shown. if (m_backward_index >= 0) { m_lookup_table.set_cursor_pos((uint)m_backward_index); m_backward_index = -1; } - show_candidate_panel(); } @@ -940,18 +928,28 @@ public class IBusEmojier : Gtk.ApplicationWindow { IBus.Text text = new IBus.Text.from_string(emoji); m_lookup_table.append_candidate(text); } - show_candidate_panel(); } private void show_unicode_blocks() { + // Do not call remove_all_children() to work adjustment.clamp_page() + // with PageUp/Down. + // After show_candidate_panel() is called, m_category_active_index + // is saved for Escape key but m_list_box is null by + // remove_all_children(). + if (m_category_active_index >= 0 && m_list_box != null) { + var row = m_list_box.get_row_at_index(m_category_active_index); + m_list_box.select_row(row); + return; + } + if (m_category_active_index < 0) + m_category_active_index = 0; m_show_unicode = true; if (m_default_window_width == 0 && m_default_window_height == 0) get_size(out m_default_window_width, out m_default_window_height); remove_all_children(); set_fixed_size(); - m_title.set_title(_("Unicode Choice")); EPaddedLabelBox label = new EPaddedLabelBox(_("Bring back emoji choice"), Gtk.Align.CENTER, @@ -964,10 +962,10 @@ public class IBusEmojier : Gtk.ApplicationWindow { m_category_active_index = -1; m_show_unicode = false; hide_candidate_panel(); + show_all(); return true; }); m_scrolled_window = new EScrolledWindow(); - m_title.set_lang_label(""); m_vbox.add(m_scrolled_window); Gtk.Viewport viewport = new Gtk.Viewport(null, null); m_scrolled_window.add(viewport); @@ -977,9 +975,10 @@ public class IBusEmojier : Gtk.ApplicationWindow { Gtk.Adjustment adjustment = m_scrolled_window.get_vadjustment(); m_list_box.set_adjustment(adjustment); m_list_box.row_activated.connect((box, gtkrow) => { - m_category_active_index = -1; + m_category_active_index = gtkrow.get_index(); EBoxRow row = gtkrow as EBoxRow; show_unicode_for_block(row.text); + show_candidate_panel(); }); uint n = 0; @@ -1007,44 +1006,18 @@ public class IBusEmojier : Gtk.ApplicationWindow { m_list_box.unselect_all(); m_list_box.invalidate_filter(); m_list_box.set_selection_mode(Gtk.SelectionMode.SINGLE); + Gtk.ListBoxRow row = m_list_box.get_row_at_index((int)n - 1); + + // If clamp_page() would be called without the allocation signal, + // the jumping page could be failed when returns from + // show_unicode_for_block() with Escape key. + row.size_allocate.connect((w, a) => { + clamp_page(); + }); } + private void show_unicode_for_block(string block_name) { - if (!m_loaded_unicode) { - remove_all_children(); - set_fixed_size(); - m_unicode_progress_bar = new Gtk.ProgressBar(); - m_unicode_progress_bar.set_ellipsize(Pango.EllipsizeMode.MIDDLE); - m_unicode_progress_bar.set_halign(Gtk.Align.CENTER); - m_unicode_progress_bar.set_valign(Gtk.Align.CENTER); - m_vbox.add(m_unicode_progress_bar); - m_unicode_progress_bar.show(); - var hbox = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 5); - hbox.set_halign(Gtk.Align.CENTER); - hbox.set_valign(Gtk.Align.CENTER); - m_vbox.add(hbox); - var label = new Gtk.Label(_("Loading a Unicode dictionary:")); - hbox.pack_start(label, false, true, 0); - m_unicode_percent_label = new Gtk.Label(""); - hbox.pack_start(m_unicode_percent_label, false, true, 0); - hbox.show_all(); - - m_unicode_progress_object.deserialize_unicode.connect((i, n) => { - m_unicode_percent = (double)i / n; - }); - GLib.Timeout.add(100, () => { - m_unicode_progress_bar.set_fraction(m_unicode_percent); - m_unicode_percent_label.set_text( - "%.0f%%\n".printf(m_unicode_percent * 100)); - m_unicode_progress_bar.show(); - m_unicode_percent_label.show(); - if (m_loaded_unicode) { - show_unicode_for_block(block_name); - } - return !m_loaded_unicode; - }); - return; - } unichar start = 0; unichar end = 0; foreach (unowned IBus.UnicodeBlock block in m_unicode_block_list) { @@ -1055,6 +1028,7 @@ public class IBusEmojier : Gtk.ApplicationWindow { } } m_lookup_table.clear(); + m_candidate_panel_mode = true; for (unichar ch = start; ch < end; ch++) { unowned IBus.UnicodeData? data = m_unicode_to_data_dict.lookup(ch); @@ -1064,7 +1038,7 @@ public class IBusEmojier : Gtk.ApplicationWindow { m_lookup_table.append_candidate(text); } m_backward = block_name; - show_candidate_panel(); + m_annotation = m_lookup_table.get_candidate(0).text; } @@ -1091,6 +1065,41 @@ public class IBusEmojier : Gtk.ApplicationWindow { prev_button.set_relief(Gtk.ReliefStyle.NONE); prev_button.set_tooltip_text(_("Page Up")); + var menu = new GLib.Menu(); + menu.append(_("Show emoji variants"), "win.variant"); + menu.append(_("Close"), "win.close"); + var menu_button = new Gtk.MenuButton(); + menu_button.set_direction(Gtk.ArrowType.NONE); + menu_button.set_valign(Gtk.Align.CENTER); + menu_button.set_menu_model(menu); + menu_button.set_relief(Gtk.ReliefStyle.NONE); + menu_button.set_tooltip_text(_("Menu")); + + IBus.Text text = this.get_title_text(); + Pango.AttrList attrs = get_pango_attr_list_from_ibus_text(text); + Gtk.Label title_label = new Gtk.Label(text.get_text()); + title_label.set_attributes(attrs); + + Gtk.Button? warning_button = null; + if (m_warning_message != "") { + warning_button = new Gtk.Button(); + warning_button.set_tooltip_text( + _("Click to view a warning message")); + warning_button.set_image(new Gtk.Image.from_icon_name( + "dialog-warning", + Gtk.IconSize.MENU)); + warning_button.set_relief(Gtk.ReliefStyle.NONE); + warning_button.clicked.connect(() => { + Gtk.Label warning_label = new Gtk.Label(m_warning_message); + warning_label.set_line_wrap(true); + warning_label.set_max_width_chars(40); + Gtk.Popover popover = new Gtk.Popover(warning_button); + popover.add(warning_label); + popover.show_all(); + popover.popup(); + }); + } + Gtk.Box buttons_hbox = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 0); Gtk.Label state_label = new Gtk.Label(null); state_label.set_size_request(10, -1); @@ -1099,14 +1108,55 @@ public class IBusEmojier : Gtk.ApplicationWindow { buttons_hbox.pack_start(state_label, false, true, 0); buttons_hbox.pack_start(prev_button, false, false, 0); buttons_hbox.pack_start(next_button, false, false, 0); + buttons_hbox.pack_start(title_label, false, false, 0); + if (warning_button != null) + buttons_hbox.pack_start(warning_button, false, false, 0); + buttons_hbox.pack_end(menu_button, false, false, 0); m_vbox.pack_start(buttons_hbox, false, false, 0); buttons_hbox.show_all(); } - private bool check_unicode_point() { - string annotation = m_entry.get_text(); - m_unicode_point = null; + private void show_unicode_progress_bar() { + m_unicode_progress_bar = new Gtk.ProgressBar(); + m_unicode_progress_bar.set_ellipsize(Pango.EllipsizeMode.MIDDLE); + m_unicode_progress_bar.set_halign(Gtk.Align.CENTER); + m_unicode_progress_bar.set_valign(Gtk.Align.CENTER); + m_vbox.add(m_unicode_progress_bar); + m_unicode_progress_bar.show(); + var hbox = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 5); + hbox.set_halign(Gtk.Align.CENTER); + hbox.set_valign(Gtk.Align.CENTER); + m_vbox.add(hbox); + var label = new Gtk.Label(_("Loading a Unicode dictionary:")); + hbox.pack_start(label, false, true, 0); + m_unicode_percent_label = new Gtk.Label(""); + hbox.pack_start(m_unicode_percent_label, false, true, 0); + hbox.show_all(); + + m_unicode_progress_object.deserialize_unicode.connect((i, n) => { + m_unicode_percent = (double)i / n; + }); + if (m_unicode_progress_id > 0) { + GLib.Source.remove(m_unicode_progress_id); + } + m_unicode_progress_id = GLib.Timeout.add(100, () => { + m_unicode_progress_id = 0; + m_unicode_progress_bar.set_fraction(m_unicode_percent); + m_unicode_percent_label.set_text( + "%.0f%%\n".printf(m_unicode_percent * 100)); + m_unicode_progress_bar.show(); + m_unicode_percent_label.show(); + if (m_loaded_unicode) { + show_candidate_panel(); + } + return !m_loaded_unicode; + }); + } + + + private static string? check_unicode_point(string annotation) { + string unicode_point = null; // Add "0x" because uint64.ascii_strtoull() is not accessible // and need to use uint64.parse() var buff = new GLib.StringBuilder("0x"); @@ -1114,33 +1164,31 @@ public class IBusEmojier : Gtk.ApplicationWindow { for (int i = 0; i < annotation.char_count(); i++) { unichar ch = annotation.get_char(i); if (ch == 0) - return false; + return null; if (ch.isspace()) { unichar code = (unichar)uint64.parse(buff.str); buff.assign("0x"); if (!code.validate()) - return false; + return null; retval.append(code.to_string()); continue; } if (!ch.isxdigit()) - return false; + return null; buff.append_unichar(ch); } unichar code = (unichar)uint64.parse(buff.str); if (!code.validate()) - return false; + return null; retval.append(code.to_string()); - m_unicode_point = retval.str; - if (m_unicode_point == null) - return true; - IBus.Text text = new IBus.Text.from_string(m_unicode_point); - m_lookup_table.append_candidate(text); - return true; + unicode_point = retval.str; + if (unicode_point == null) + return null; + return unicode_point; } - private GLib.SList<string>? + private static GLib.SList<string>? lookup_emojis_from_annotation(string annotation) { GLib.SList<string>? total_emojis = null; unowned GLib.SList<string>? sub_emojis = null; @@ -1221,19 +1269,19 @@ public class IBusEmojier : Gtk.ApplicationWindow { return total_emojis; } + private void update_candidate_window() { - string annotation = m_entry.get_text(); + string annotation = m_annotation; if (annotation.length == 0) { - hide_candidate_panel(); m_backward = null; return; } + m_lookup_table.clear(); + m_category_active_index = -1; if (annotation.length > m_emoji_max_seq_len) { - hide_candidate_panel(); return; } - // Call check_unicode_point() to get m_unicode_point - check_unicode_point(); + string? unicode_point = check_unicode_point(annotation); GLib.SList<string>? total_emojis = lookup_emojis_from_annotation(annotation); if (total_emojis == null) { @@ -1246,18 +1294,75 @@ public class IBusEmojier : Gtk.ApplicationWindow { annotation = annotation.down(); total_emojis = lookup_emojis_from_annotation(annotation); } - if (total_emojis == null && m_unicode_point == null) { - hide_candidate_panel(); + if (total_emojis == null && unicode_point == null) { return; } - m_lookup_table.clear(); - // Call check_unicode_point() to update m_lookup_table - check_unicode_point(); + if (unicode_point != null) { + IBus.Text text = new IBus.Text.from_string(unicode_point); + m_lookup_table.append_candidate(text); + } foreach (unowned string emoji in total_emojis) { IBus.Text text = new IBus.Text.from_string(emoji); m_lookup_table.append_candidate(text); } - show_candidate_panel(); + m_candidate_panel_is_visible = + (m_lookup_table.get_number_of_candidates() > 0) ? true : false; + m_candidate_panel_mode = true; + } + + + private void update_category_list() { + // Always update m_lookup_table even if the contents are same + // because m_category_active_index needs to be kept after + // bring back this API from show_emoji_for_category(). + reset_window_mode(); + m_lookup_table.clear(); + IBus.Text text; + if (m_favorites.length > 0) { + text = new IBus.Text.from_string(EMOJI_CATEGORY_FAVORITES); + m_lookup_table.append_candidate(text); + } + GLib.List<unowned string> categories = + m_category_to_emojis_dict.get_keys(); + // FIXME: How to cast GLib.CompareFunc<string> to strcmp? + categories.sort((a, b) => { + if (a == EMOJI_CATEGORY_OTHERS && b != EMOJI_CATEGORY_OTHERS) + return 1; + else if (a != EMOJI_CATEGORY_OTHERS && b == EMOJI_CATEGORY_OTHERS) + return -1; + return GLib.strcmp(_(a), _(b)); + }); + foreach (unowned string category in categories) { + // "Others" category includes next unicode chars and fonts do not + // support the base and varints yet. + if (category == EMOJI_CATEGORY_OTHERS) + continue; + text = new IBus.Text.from_string(category); + m_lookup_table.append_candidate(text); + } + if (m_unicode_block_list.length() > 0) { + text = new IBus.Text.from_string(EMOJI_CATEGORY_UNICODE); + m_lookup_table.append_candidate(text); + } + // Do not set m_category_active_index to 0 here so that + // show_category_list() handles it. + } + + + private void update_unicode_blocks() { + // Always update m_lookup_table even if the contents are same + // because m_category_active_index needs to be kept after + // bring back this API from show_emoji_for_category(). + reset_window_mode(); + m_lookup_table.clear(); + m_show_unicode = true; + foreach (unowned IBus.UnicodeBlock block in m_unicode_block_list) { + string name = block.get_name(); + IBus.Text text = new IBus.Text.from_string(name); + m_lookup_table.append_candidate(text); + } + // Do not set m_category_active_index to 0 here so that + // show_unicode_blocks() handles it. } @@ -1283,27 +1388,27 @@ public class IBusEmojier : Gtk.ApplicationWindow { uint page_size = m_lookup_table.get_page_size(); uint ncandidates = m_lookup_table.get_number_of_candidates(); uint cursor = m_lookup_table.get_cursor_pos(); - uint page_start_pos = cursor / page_size * page_size; uint page_end_pos = uint.min(page_start_pos + page_size, ncandidates); + Gtk.Button? backward_button = null; if (m_backward != null) { - string backward_desc = - "%s (%u / %u)".printf(_(m_backward), cursor, ncandidates - 1); + string backward_desc = _(m_backward); EPaddedLabelBox label = new EPaddedLabelBox(backward_desc, Gtk.Align.CENTER, TravelDirection.BACKWARD); - Gtk.Button button = new Gtk.Button(); - button.add(label); - m_vbox.add(button); - button.show_all(); - button.button_press_event.connect((w, e) => { + backward_button = new Gtk.Button(); + backward_button.add(label); + backward_button.button_press_event.connect((w, e) => { // Bring back to emoji candidate panel in case // m_show_emoji_variant is enabled and shows variants. - if (m_backward_index >= 0 && m_backward != null) + if (m_backward_index >= 0 && m_backward != null) { show_emoji_for_category(m_backward); - else + show_candidate_panel(); + } else { hide_candidate_panel(); + show_all(); + } return true; }); } @@ -1385,34 +1490,60 @@ public class IBusEmojier : Gtk.ApplicationWindow { } if (n > 0) { m_candidate_panel_is_visible = true; - show_arrow_buttons(); - m_vbox.add(grid); - grid.show_all(); - string text = m_lookup_table.get_candidate(cursor).text; - unowned IBus.EmojiData? data = m_emoji_to_data_dict.lookup(text); - if (data != null) { - show_emoji_description(data, text); - return; + if (!m_is_up_side_down) { + show_arrow_buttons(); + if (backward_button != null) { + m_vbox.add(backward_button); + backward_button.show_all(); + } + m_vbox.add(grid); + grid.show_all(); + show_description(); + if (!m_loaded_unicode) + show_unicode_progress_bar(); } - if (text.char_count() <= 1) { - unichar code = text.get_char(); - unowned IBus.UnicodeData? udata = - m_unicode_to_data_dict.lookup(code); - if (udata != null) { - show_unicode_description(udata, text); - return; + if (m_is_up_side_down) { + if (!m_loaded_unicode) + show_unicode_progress_bar(); + show_description(); + m_vbox.add(grid); + grid.show_all(); + if (backward_button != null) { + m_vbox.add(backward_button); + backward_button.show_all(); } + show_arrow_buttons(); } - EPaddedLabelBox widget = new EPaddedLabelBox( - _("Description: %s").printf(_("None")), - Gtk.Align.START); - m_vbox.add(widget); - widget.show_all(); - show_code_point_description(text); } } + private void show_description() { + uint cursor = m_lookup_table.get_cursor_pos(); + string text = m_lookup_table.get_candidate(cursor).text; + unowned IBus.EmojiData? data = m_emoji_to_data_dict.lookup(text); + if (data != null) { + show_emoji_description(data, text); + return; + } + if (text.char_count() <= 1) { + unichar code = text.get_char(); + unowned IBus.UnicodeData? udata = + m_unicode_to_data_dict.lookup(code); + if (udata != null) { + show_unicode_description(udata, text); + return; + } + } + EPaddedLabelBox widget = new EPaddedLabelBox( + _("Description: %s").printf(_("None")), + Gtk.Align.START); + m_vbox.add(widget); + widget.show_all(); + show_code_point_description(text); + } + + private void show_emoji_description(IBus.EmojiData data, string text) { unowned string description = data.get_description(); @@ -1473,14 +1604,17 @@ public class IBusEmojier : Gtk.ApplicationWindow { private void hide_candidate_panel() { + hide(); m_enter_notify_enable = true; - m_candidate_panel_is_visible = false; - if (m_loop.is_running()) { - if (m_show_unicode) - show_unicode_blocks(); - else - show_category_list(); - } + m_annotation = ""; + // Call remove_all_children() instead of show_category_list() + // so that show_category_list do not remove children with + // PageUp/PageDown. + remove_all_children(); + if (m_show_unicode) + update_unicode_blocks(); + else + update_category_list(); } @@ -1498,20 +1632,34 @@ public class IBusEmojier : Gtk.ApplicationWindow { } - private void candidate_panel_select_index(uint index) { + private void candidate_panel_select_index(uint index, + uint button) { + if (button == BUTTON_CLOSE_BUTTON) { + hide(); + if (m_candidate_panel_mode && + m_lookup_table.get_number_of_candidates() > 0) { + // Call remove_all_children() instead of show_category_list() + // so that show_category_list do not remove children with + // PageUp/PageDown. + remove_all_children(); + } + m_result = ""; + return; + } string text = m_lookup_table.get_candidate(index).text; unowned GLib.SList<string>? emojis = m_emoji_to_emoji_variants_dict.lookup(text); if (m_show_emoji_variant && emojis != null && m_backward_index < 0) { show_emoji_variants(emojis); + show_all(); } else { m_result = text; - m_loop.quit(); - hide_candidate_panel(); + hide(); } } + private void candidate_panel_cursor_down() { enter_notify_disable_with_timer(); uint ncandidates = m_lookup_table.get_number_of_candidates(); @@ -1523,7 +1671,6 @@ public class IBusEmojier : Gtk.ApplicationWindow { } else { m_lookup_table.set_cursor_pos(0); } - show_candidate_panel(); } @@ -1541,7 +1688,6 @@ public class IBusEmojier : Gtk.ApplicationWindow { } else { m_lookup_table.set_cursor_pos(0); } - show_candidate_panel(); } @@ -1558,7 +1704,9 @@ public class IBusEmojier : Gtk.ApplicationWindow { return page_num; } + private bool category_list_cursor_move(uint keyval) { + return_val_if_fail (m_list_box != null, false); GLib.List<weak Gtk.Widget> list = m_list_box.get_children(); int length = (int)list.length(); if (length == 0) @@ -1600,32 +1748,37 @@ public class IBusEmojier : Gtk.ApplicationWindow { var row = m_list_box.get_selected_row(); if (row != null) m_list_box.unselect_row(row); - if (m_category_active_index >= 0) { - row = m_list_box.get_row_at_index(m_category_active_index); - m_list_box.select_row(row); - } else { - row = m_list_box.get_row_at_index(0); - } - Gtk.Allocation alloc = { 0, 0, 0, 0 }; - row.get_allocation(out alloc); - var adjustment = m_scrolled_window.get_vadjustment(); - adjustment.clamp_page(alloc.y, alloc.y + alloc.height); + clamp_page (); return true; } - private bool key_press_cursor_horizontal(uint keyval, - uint modifiers) { + public bool has_variants(uint index) { + if (index >= m_lookup_table.get_number_of_candidates()) + return false; + string text = m_lookup_table.get_candidate(index).text; + unowned GLib.SList<string>? emojis = + m_emoji_to_emoji_variants_dict.lookup(text); + if (m_show_emoji_variant && emojis != null && + m_backward_index < 0) { + show_emoji_variants(emojis); + return true; + } + return false; + } + + + public bool key_press_cursor_horizontal(uint keyval, + uint modifiers) { assert (keyval == Gdk.Key.Left || keyval == Gdk.Key.Right); - uint ncandidates = m_lookup_table.get_number_of_candidates(); - if (m_candidate_panel_is_visible && ncandidates > 1) { + if (m_candidate_panel_mode && + m_lookup_table.get_number_of_candidates() > 0) { enter_notify_disable_with_timer(); if (keyval == Gdk.Key.Left) m_lookup_table.cursor_up(); else if (keyval == Gdk.Key.Right) m_lookup_table.cursor_down(); - show_candidate_panel(); } else if (m_entry.get_text().length > 0) { int step = 0; if (keyval == Gdk.Key.Left) @@ -1650,8 +1803,8 @@ public class IBusEmojier : Gtk.ApplicationWindow { } - private bool key_press_cursor_vertical(uint keyval, - uint modifiers) { + public bool key_press_cursor_vertical(uint keyval, + uint modifiers) { assert (keyval == Gdk.Key.Down || keyval == Gdk.Key.Up || keyval == Gdk.Key.Page_Down || keyval == Gdk.Key.Page_Up); @@ -1661,8 +1814,8 @@ public class IBusEmojier : Gtk.ApplicationWindow { else if (keyval == Gdk.Key.Up) keyval = Gdk.Key.Page_Up; } - uint ncandidates = m_lookup_table.get_number_of_candidates(); - if (m_candidate_panel_is_visible && ncandidates > 1) { + if ((m_candidate_panel_is_visible || m_annotation.length > 0) + && m_lookup_table.get_number_of_candidates() > 0) { switch (keyval) { case Gdk.Key.Down: candidate_panel_cursor_down(); @@ -1673,12 +1826,10 @@ public class IBusEmojier : Gtk.ApplicationWindow { case Gdk.Key.Page_Down: enter_notify_disable_with_timer(); m_lookup_table.page_down(); - show_candidate_panel(); break; case Gdk.Key.Page_Up: enter_notify_disable_with_timer(); m_lookup_table.page_up(); - show_candidate_panel(); break; } } else { @@ -1688,19 +1839,18 @@ public class IBusEmojier : Gtk.ApplicationWindow { } - private bool key_press_cursor_home_end(uint keyval, - uint modifiers) { + public bool key_press_cursor_home_end(uint keyval, + uint modifiers) { assert (keyval == Gdk.Key.Home || keyval == Gdk.Key.End); uint ncandidates = m_lookup_table.get_number_of_candidates(); - if (m_candidate_panel_is_visible && ncandidates > 1) { + if (m_candidate_panel_mode && ncandidates > 0) { enter_notify_disable_with_timer(); if (keyval == Gdk.Key.Home) { m_lookup_table.set_cursor_pos(0); } else if (keyval == Gdk.Key.End) { m_lookup_table.set_cursor_pos(ncandidates - 1); } - show_candidate_panel(); return true; } if (m_entry.get_text().length > 0) { @@ -1717,44 +1867,41 @@ public class IBusEmojier : Gtk.ApplicationWindow { ? true : false); return true; } - if (!m_candidate_panel_is_visible) - return category_list_cursor_move(keyval); - return false; + return category_list_cursor_move(keyval); } - private bool key_press_escape() { + public bool key_press_escape() { if (m_show_unicode) { - if (m_candidate_panel_is_visible) { - m_candidate_panel_is_visible = false; - show_unicode_blocks(); - return true; - } else { + if (!m_candidate_panel_is_visible) { m_show_unicode = false; m_category_active_index = -1; - hide_candidate_panel(); - return true; } + hide_candidate_panel(); + return true; } else if (m_backward_index >= 0 && m_backward != null) { show_emoji_for_category(m_backward); return true; - } else if (m_candidate_panel_is_visible) { - hide_candidate_panel(); - return true; - } else if (m_entry.get_text().length == 0) { - m_loop.quit(); + } else if (m_candidate_panel_is_visible && m_backward != null) { hide_candidate_panel(); return true; } - m_entry.delete_text(0, -1); - return true; + hide(); + if (m_candidate_panel_mode && + m_lookup_table.get_number_of_candidates() > 0) { + // Call remove_all_children() instead of show_category_list() + // so that show_category_list do not remove children with + // PageUp/PageDown. + remove_all_children(); + } + return false; } - private bool key_press_enter() { + public bool key_press_enter() { if (m_candidate_panel_is_visible) { uint index = m_lookup_table.get_cursor_pos(); - candidate_panel_select_index(index); + return has_variants(index); } else if (m_category_active_index >= 0) { Gtk.ListBoxRow gtkrow = m_list_box.get_selected_row(); EBoxRow row = gtkrow as EBoxRow; @@ -1789,13 +1936,111 @@ public class IBusEmojier : Gtk.ApplicationWindow { } + private Gdk.Rectangle get_monitor_geometry() { + Gdk.Rectangle monitor_area = { 0, }; + + // Use get_monitor_geometry() instead of get_monitor_area(). + // get_monitor_area() excludes docks, but the lookup window should be + // shown over them. +#if VALA_0_34 + Gdk.Monitor monitor = Gdk.Display.get_default().get_monitor_at_point( + m_cursor_location.x, + m_cursor_location.y); + monitor_area = monitor.get_geometry(); +#else + Gdk.Screen screen = Gdk.Screen.get_default(); + int monitor_num = screen.get_monitor_at_point(m_cursor_location.x, + m_cursor_location.y); + screen.get_monitor_geometry(monitor_num, out monitor_area); +#endif + return monitor_area; + } + + + private void adjust_window_position() { + Gdk.Point cursor_right_bottom = { + m_cursor_location.x + m_cursor_location.width, + m_cursor_location.y + m_cursor_location.height + }; + + Gtk.Allocation allocation; + get_allocation(out allocation); + Gdk.Point window_right_bottom = { + cursor_right_bottom.x + allocation.width, + cursor_right_bottom.y + allocation.height + }; + + Gdk.Rectangle monitor_area = get_monitor_geometry(); + int monitor_right = monitor_area.x + monitor_area.width; + int monitor_bottom = monitor_area.y + monitor_area.height; + + int x, y; + if (window_right_bottom.x > monitor_right) + x = monitor_right - allocation.width; + else + x = cursor_right_bottom.x; + if (x < 0) + x = 0; + + bool changed = false; + if (window_right_bottom.y > monitor_bottom) { + y = m_cursor_location.y - allocation.height; + // Do not up side down in Wayland + if (m_input_context_path == "") { + changed = (m_is_up_side_down == false); + m_is_up_side_down = true; + } else { + changed = (m_is_up_side_down == true); + m_is_up_side_down = false; + } + } else { + y = cursor_right_bottom.y; + changed = (m_is_up_side_down == true); + m_is_up_side_down = false; + } + if (y < 0) + y = 0; + + move(x, y); + if (changed) { + if (m_redraw_window_id > 0) + GLib.Source.remove(m_redraw_window_id); + m_redraw_window_id = GLib.Timeout.add(100, () => { + m_redraw_window_id = 0; + this.show_all(); + return false; + }); + } + } + + +#if 0 + private void check_action_variant_cb(Gtk.MenuItem item) { + Gtk.CheckMenuItem check = item as Gtk.CheckMenuItem; + m_show_emoji_variant = check.get_active(); + // Redraw emoji candidate panel for m_show_emoji_variant + if (m_candidate_panel_is_visible) { + // DOTO: queue_draw() does not effect at the real time. + this.queue_draw(); + } + } +#else private void check_action_variant_cb(GLib.SimpleAction action, GLib.Variant? parameter) { m_show_emoji_variant = !action.get_state().get_boolean(); action.set_state(new GLib.Variant.boolean(m_show_emoji_variant)); // Redraw emoji candidate panel for m_show_emoji_variant - if (m_candidate_panel_is_visible) - show_candidate_panel(); + if (m_candidate_panel_is_visible) { + // DOTO: queue_draw() does not effect at the real time. + this.queue_draw(); + } + } +#endif + + + private void action_close_cb(GLib.SimpleAction action, + GLib.Variant? parameter) { + candidate_clicked(0, BUTTON_CLOSE_BUTTON, 0); } @@ -1842,6 +2087,123 @@ public class IBusEmojier : Gtk.ApplicationWindow { } + public void set_annotation(string annotation) { + m_annotation = annotation; + remove_all_children(); + if (annotation.length > 0) { + update_candidate_window(); + } else { + if (m_show_unicode) + update_unicode_blocks(); + else + update_category_list(); + } + } + + + public IBus.LookupTable get_one_dimension_lookup_table() { + var lookup_table = new IBus.LookupTable(EMOJI_GRID_PAGE, 0, true, true); + uint i = 0; + for (; i < m_lookup_table.get_number_of_candidates(); i++) { + IBus.Text text = new IBus.Text.from_string(""); + text.copy(m_lookup_table.get_candidate(i)); + lookup_table.append_candidate(text); + } + if (i > 0) + lookup_table.set_cursor_pos(m_lookup_table.get_cursor_pos()); + return lookup_table; + } + + + public uint get_number_of_candidates() { + return m_lookup_table.get_number_of_candidates(); + } + + + public uint get_cursor_pos() { + return m_lookup_table.get_cursor_pos(); + } + + + public void set_cursor_pos(uint cursor_pos) { + m_lookup_table.set_cursor_pos(cursor_pos); + } + + + public string get_current_candidate() { + // If category_list mode, do not show the category name on preedit. + // If candidate_panel mode, the first space key does not show the + // lookup table but the first candidate is avaiable on preedit. + if (!m_candidate_panel_mode) + return ""; + uint cursor = m_lookup_table.get_cursor_pos(); + return m_lookup_table.get_candidate(cursor).text; + } + + + public IBus.Text get_title_text() { + var language = _(IBus.get_language_name(m_current_lang_id)); + uint ncandidates = this.get_number_of_candidates(); + string main_title = _("Emoji Choice"); + if (m_show_unicode) + main_title = _("Unicode Choice"); + var text = new IBus.Text.from_string( + "%s (%s) (%u / %u)".printf( + main_title, + language, + this.get_cursor_pos() + 1, + ncandidates)); + int char_count = text.text.char_count(); + int start_index = -1; + for (int i = 0; i < char_count; i++) { + if (text.text.utf8_offset(i).has_prefix(language)) { + start_index = i; + break; + } + } + if (start_index >= 0) { + var attr = new IBus.Attribute( + IBus.AttrType.FOREGROUND, + 0x808080, + start_index, + start_index + language.char_count()); + var attrs = new IBus.AttrList(); + attrs.append(attr); + text.set_attributes(attrs); + } + return text; + } + + +#if 0 + public GLib.SList<string>? get_candidates() { + if (m_annotation.length == 0) { + return null; + } + if (m_annotation.length > m_emoji_max_seq_len) { + return null; + } + string? unicode_point = check_unicode_point(m_annotation); + GLib.SList<string>? total_emojis = + lookup_emojis_from_annotation(m_annotation); + if (total_emojis == null) { + /* Users can type title strings against lower case. + * E.g. "Smile" against "smile" + * But the dictionary has the case sensitive annotations. + * E.g. ":D" and ":q" + * So need to call lookup_emojis_from_annotation() twice. + */ + string lower_annotation = m_annotation.down(); + total_emojis = lookup_emojis_from_annotation(lower_annotation); + } + if (unicode_point != null) + total_emojis.prepend(unicode_point); + return total_emojis; + } +#endif + + +#if 0 public string run(string input_context_path, Gdk.Event event) { assert (m_loop == null); @@ -1915,12 +2277,34 @@ public class IBusEmojier : Gtk.ApplicationWindow { return m_result; } +#endif /* override virtual functions */ - public override void show() { - base.show(); - set_focus_visible(true); + public override void show_all() { + base.show_all(); + if (m_candidate_panel_mode) + show_candidate_panel(); + else if (m_show_unicode) + show_unicode_blocks(); + else + show_category_list(); + } + + + public override void hide() { + base.hide(); + m_candidate_panel_is_visible = false; + // m_candidate_panel_mode is not false in when you type something + // during enabling the candidate panel. + if (m_redraw_window_id > 0) { + GLib.Source.remove(m_redraw_window_id); + m_redraw_window_id = 0; + } + if (m_unicode_progress_id > 0) { + GLib.Source.remove(m_unicode_progress_id); + m_unicode_progress_id = 0; + } } @@ -1935,11 +2319,16 @@ public class IBusEmojier : Gtk.ApplicationWindow { switch (keyval) { case Gdk.Key.Escape: if (key_press_escape()) - return true; - break; + show_all(); + return true; case Gdk.Key.Return: case Gdk.Key.KP_Enter: - key_press_enter(); + if (key_press_enter()) { + show_all(); + } else { + m_result = get_current_candidate(); + hide(); + } return true; case Gdk.Key.BackSpace: if (m_entry.get_text().length > 0) { @@ -1977,42 +2366,49 @@ public class IBusEmojier : Gtk.ApplicationWindow { } else { category_list_cursor_move(Gdk.Key.Down); + show_all(); } return true; case Gdk.Key.Right: case Gdk.Key.KP_Right: key_press_cursor_horizontal(Gdk.Key.Right, modifiers); + show_all(); return true; case Gdk.Key.Left: case Gdk.Key.KP_Left: key_press_cursor_horizontal(Gdk.Key.Left, modifiers); + show_all(); return true; case Gdk.Key.Down: case Gdk.Key.KP_Down: key_press_cursor_vertical(Gdk.Key.Down, modifiers); + show_all(); return true; case Gdk.Key.Up: case Gdk.Key.KP_Up: key_press_cursor_vertical(Gdk.Key.Up, modifiers); + show_all(); return true; case Gdk.Key.Page_Down: case Gdk.Key.KP_Page_Down: key_press_cursor_vertical(Gdk.Key.Page_Down, modifiers); + show_all(); return true; case Gdk.Key.Page_Up: case Gdk.Key.KP_Page_Up: key_press_cursor_vertical(Gdk.Key.Page_Up, modifiers); + show_all(); return true; case Gdk.Key.Home: case Gdk.Key.KP_Home: - if (key_press_cursor_home_end(Gdk.Key.Home, modifiers)) - return true; - break; + key_press_cursor_home_end(Gdk.Key.Home, modifiers); + show_all(); + return true; case Gdk.Key.End: case Gdk.Key.KP_End: - if (key_press_cursor_home_end(Gdk.Key.End, modifiers)) - return true; - break; + key_press_cursor_home_end(Gdk.Key.End, modifiers); + show_all(); + return true; case Gdk.Key.Insert: case Gdk.Key.KP_Insert: GLib.Signal.emit_by_name(m_entry, "toggle-overwrite"); @@ -2023,26 +2419,30 @@ public class IBusEmojier : Gtk.ApplicationWindow { switch (keyval) { case Gdk.Key.f: key_press_cursor_horizontal(Gdk.Key.Right, modifiers); + show_all(); return true; case Gdk.Key.b: key_press_cursor_horizontal(Gdk.Key.Left, modifiers); + show_all(); return true; case Gdk.Key.n: case Gdk.Key.N: key_press_cursor_vertical(Gdk.Key.Down, modifiers); + show_all(); return true; case Gdk.Key.p: case Gdk.Key.P: key_press_cursor_vertical(Gdk.Key.Up, modifiers); + show_all(); return true; case Gdk.Key.h: - if (key_press_cursor_home_end(Gdk.Key.Home, modifiers)) - return true; - break; + key_press_cursor_home_end(Gdk.Key.Home, modifiers); + show_all(); + return true; case Gdk.Key.e: - if (key_press_cursor_home_end(Gdk.Key.End, modifiers)) - return true; - break; + key_press_cursor_home_end(Gdk.Key.End, modifiers); + show_all(); + return true; case Gdk.Key.u: if (m_entry.get_text().length > 0) { GLib.Signal.emit_by_name(m_entry, @@ -2103,14 +2503,41 @@ public class IBusEmojier : Gtk.ApplicationWindow { } + public void set_input_context_path(string input_context_path) { + m_input_context_path = input_context_path; + if (input_context_path == "") { + m_warning_message = _("" + + "Failed to get the current text application. " + + "Please re-focus your application. E.g. Press Esc key " + + "several times to release the emoji typing mode, " + + "click your desktop and click your text application again." + ); + } else { + m_warning_message = ""; + } + } + + public string get_selected_string() { return m_result; } + private void reset_window_mode() { + m_backward_index = -1; + m_backward = null; + m_candidate_panel_is_visible = false; + m_candidate_panel_mode = false; + // Do not clear m_lookup_table to work with space key later. + } + + public void reset() { + reset_window_mode(); m_input_context_path = ""; m_result = null; + m_category_active_index = -1; + m_show_unicode = false; } @@ -2145,6 +2572,23 @@ public class IBusEmojier : Gtk.ApplicationWindow { } + public void set_cursor_location(int x, + int y, + int width, + int height) { + Gdk.Rectangle location = Gdk.Rectangle(){ + x = x, y = y, width = width, height = height }; + if (m_cursor_location == location) + return; + m_cursor_location = location; + } + + + public bool is_candidate_panel_mode() { + return m_candidate_panel_mode; + } + + public static bool has_loaded_emoji_dict() { if (m_emoji_to_data_dict == null) return false; @@ -2165,6 +2609,10 @@ public class IBusEmojier : Gtk.ApplicationWindow { } + public static string get_annotation_lang() { + return m_current_lang_id; + } + public static void set_emoji_font(string? emoji_font) { return_if_fail(emoji_font != null && emoji_font != ""); Pango.FontDescription font_desc = @@ -2182,18 +2630,21 @@ public class IBusEmojier : Gtk.ApplicationWindow { m_has_partial_match = has_partial_match; } + public static void set_partial_match_length(int length) { if (length < 1) return; m_partial_match_length = length; } + public static void set_partial_match_condition(int condition) { if (condition < 0) return; m_partial_match_condition = condition; } + public static void set_favorites(string[]? unowned_favorites, string[]? unowned_favorite_annotations) { m_favorites = {}; |