Commit e469d594 authored by Sébastien Lafargue's avatar Sébastien Lafargue Committed by Sébastien Lafargue
Browse files

spellcheck: spell widget

parent 24b84ca4
......@@ -8,6 +8,7 @@
"clear-count" ()
"clear-snippets" ()
"hide-completion" () };
bind "<shift>F7" { "action" ("frame", "spellcheck", "1") };
bind "<ctrl>f" { "action" ("frame", "find", "3") };
bind "<ctrl>h" { "action" ("frame", "find-replace", "3") };
bind "<ctrl>o" { "action" ("win", "open-with-dialog", "") };
......
......@@ -59,6 +59,7 @@
bind "<alt>x" { "action" ("win", "show-command-bar", "") };
bind "<ctrl>r" { "action" ("frame", "find", "2") };
bind "<ctrl>s" { "action" ("frame", "find", "3") };
bind "<alt>dollar" { "action" ("frame", "spellcheck", "1") };
bind "<alt>period" { "goto-definition" () };
bind "<alt>n" { "move-error" (down) };
bind "<alt>p" { "move-error" (up) };
......
......@@ -178,6 +178,8 @@
/* start search backward */
bind "question" { "action" ("frame", "find", "2") };
/* start spell checking */
bind "<shift>F7" { "action" ("frame", "spellcheck", "1") };
/* start search */
bind "slash" { "action" ("frame", "find", "3") };
bind "KP_Divide" { "action" ("frame", "find", "3") };
......
......@@ -3,8 +3,8 @@ filechooser actionbar button.combo {
padding: 0;
}
/* styling for editor search */
frame.gb-search-frame {
/* styling for editor search and spellchecker */
frame.gb-search-frame, frame.gb-spell-frame {
background-image: linear-gradient(shade(@theme_bg_color,1.05), @theme_bg_color);
padding: 6px;
border-style: solid;
......@@ -15,36 +15,51 @@ frame.gb-search-frame {
border-bottom-left-radius: 5px;
border-bottom-right-radius: 5px;
}
frame.gb-search-frame border {
frame.gb-search-frame border,
frame.gb-spell-frame border {
border: none;
}
/* styling for the search frame close button */
frame.gb-spell-frame list {
border: 1px solid @borders;
}
frame.gb-spell-option-frame border {
border: 1px solid @borders;
}
/* styling for the search and spellchecker frame close button */
frame.gb-search-frame > box > grid:first-child > button.close:disabled,
frame.gb-search-frame > box > grid:first-child > button.close {
frame.gb-spell-frame > box > grid:first-child > button.close:disabled,
frame.gb-search-frame > box > grid:first-child > button.close,
frame.gb-spell-frame > box > grid:first-child > button.close {
background: none;
border: none;
box-shadow: none;
padding-left: 4px;
padding-right: 4px;
}
frame.gb-search-frame > box > grid:first-child > button.close image {
frame.gb-search-frame > box > grid:first-child > button.close image,
frame.gb-spell-frame > box > grid:first-child > button.close image {
color: @theme_fg_color;
opacity: 0.3;
margin: 2px;
border: 1px solid transparent;
border-radius: 3px;
}
frame.gb-search-frame > box > grid:first-child > button.close:hover image {
frame.gb-search-frame > box > grid:first-child > button.close:hover image,
frame.gb-spell-frame > box > grid:first-child > button.close:hover image {
opacity: .75;
transition-duration: 250ms;
border: 1px solid @borders;
}
frame.gb-search-frame > box > grid:first-child > button.close:active image {
frame.gb-search-frame > box > grid:first-child > button.close:active image,
frame.gb-spell-frame > box > grid:first-child > button.close:active image {
opacity: .8;
background-image: linear-gradient(shade(@theme_bg_color, 0.9), @theme_bg_color);
}
frame.gb-search-frame > box > grid:first-child > button.close:backdrop image {
frame.gb-search-frame > box > grid:first-child > button.close:backdrop image,
frame.gb-spell-frame > box > grid:first-child > button.close:backdrop image {
opacity: .1;
}
......
......@@ -388,6 +388,8 @@ libide_1_0_la_SOURCES = \
editor/ide-editor-layout-stack-controls.h \
editor/ide-editor-print-operation.c \
editor/ide-editor-print-operation.h \
editor/ide-editor-spell-widget.c \
editor/ide-editor-spell-widget.h \
editor/ide-editor-tweak-widget.c \
editor/ide-editor-tweak-widget.h \
editor/ide-editor-view-actions.c \
......
......@@ -20,8 +20,59 @@
#include "ide-editor-frame-actions.h"
#include "ide-editor-frame-private.h"
#include "ide-editor-spell-widget.h"
#include "util/ide-gtk.h"
static void
ide_editor_frame_actions_spellcheck (GSimpleAction *action,
GVariant *variant,
gpointer user_data)
{
IdeEditorFrame *self = user_data;
GtkWidget *spell_widget;
GtkWidget *entry;
g_assert (IDE_IS_EDITOR_FRAME (self));
if (IDE_IS_SOURCE_VIEW (self->source_view) &&
!self->spellchecker_opened)
{
g_assert (gtk_bin_get_child (GTK_BIN (self->spell_revealer)) == NULL);
self->spellchecker_opened = TRUE;
spell_widget = ide_editor_spell_widget_new (self->source_view);
gtk_widget_show (spell_widget);
gtk_container_add (GTK_CONTAINER (self->spell_revealer), spell_widget);
gtk_revealer_set_reveal_child (self->spell_revealer, TRUE);
entry = ide_editor_spell_widget_get_entry (IDE_EDITOR_SPELL_WIDGET (spell_widget));
/* We need the widget to be realized before the grab to avoid:
* gtk_widget_event: assertion 'WIDGET_REALIZED_FOR_EVENT (widget, event)' failed
*/
gtk_widget_realize (entry);
gtk_widget_grab_focus (entry);
g_signal_connect_object (spell_widget,
"unmap",
G_CALLBACK (ide_editor_frame_spell_widget_unmapped_cb),
self,
G_CONNECT_SWAPPED | G_CONNECT_AFTER);
}
}
static void
ide_editor_frame_actions_exit_spell (GSimpleAction *action,
GVariant *state,
gpointer user_data)
{
IdeEditorFrame *self = user_data;
g_assert (IDE_IS_EDITOR_FRAME (self));
gtk_widget_grab_focus (GTK_WIDGET (self->source_view));
}
static void
ide_editor_frame_actions_find (GSimpleAction *action,
GVariant *variant,
......@@ -415,6 +466,7 @@ static const GActionEntry IdeEditorFrameActions[] = {
{ "next-search-result", ide_editor_frame_actions_next_search_result },
{ "previous-search-result", ide_editor_frame_actions_previous_search_result },
{ "replace-confirm", ide_editor_frame_actions_replace_confirm, "as" },
{ "spellcheck", ide_editor_frame_actions_spellcheck, "i" },
};
static const GActionEntry IdeEditorFrameSearchActions[] = {
......@@ -430,6 +482,10 @@ static const GActionEntry IdeEditorFrameSearchActions[] = {
{ "replace-all", ide_editor_frame_actions_replace_all },
};
static const GActionEntry IdeEditorFrameSpellActions[] = {
{ "exit-spell", ide_editor_frame_actions_exit_spell },
};
void
ide_editor_frame_actions_init (IdeEditorFrame *self)
{
......@@ -459,4 +515,11 @@ ide_editor_frame_actions_init (IdeEditorFrame *self)
gtk_widget_insert_action_group (GTK_WIDGET (self->search_frame), "search-entry", G_ACTION_GROUP (group));
g_object_unref (group);
group = g_simple_action_group_new ();
g_action_map_add_action_entries (G_ACTION_MAP (group), IdeEditorFrameSpellActions,
G_N_ELEMENTS (IdeEditorFrameSpellActions), self);
gtk_widget_insert_action_group (GTK_WIDGET (self->spell_revealer), "spell-entry", G_ACTION_GROUP (group));
g_object_unref (group);
}
......@@ -23,7 +23,9 @@
#include <gtk/gtk.h>
#include <nautilus-floating-bar.h>
#include "ide-types.h"
#include "editor/ide-editor-map-bin.h"
#include "ide-editor-spell-widget.h"
#include "sourceview/ide-source-map.h"
#include "sourceview/ide-source-view.h"
......@@ -41,6 +43,7 @@ struct _IdeEditorFrame
GtkLabel *overwrite_label;
GtkScrolledWindow *scrolled_window;
GtkRevealer *search_revealer;
GtkRevealer *spell_revealer;
GtkFrame *search_frame;
GdTaggedEntry *search_entry;
GtkSearchEntry *replace_entry;
......@@ -58,8 +61,12 @@ struct _IdeEditorFrame
guint pending_replace_confirm;
guint auto_hide_map : 1;
guint show_ruler : 1;
guint spellchecker_opened : 1;
};
void ide_editor_frame_spell_widget_unmapped_cb (IdeEditorFrame *self,
IdeEditorSpellWidget *spell_widget);
G_END_DECLS
#endif /* IDE_EDITOR_FRAME_PRIVATE_H */
......@@ -29,6 +29,7 @@
#include "editor/ide-editor-frame.h"
#include "editor/ide-editor-map-bin.h"
#include "editor/ide-editor-perspective.h"
#include "editor/ide-editor-spell-widget.h"
#include "history/ide-back-forward-list.h"
#include "util/ide-dnd.h"
#include "util/ide-gtk.h"
......@@ -56,6 +57,22 @@ enum {
static GParamSpec *properties [LAST_PROP];
void
ide_editor_frame_spell_widget_unmapped_cb (IdeEditorFrame *self,
IdeEditorSpellWidget *spell_widget)
{
GtkWidget *child;
g_assert (IDE_IS_EDITOR_FRAME (self));
g_assert (IDE_IS_EDITOR_SPELL_WIDGET (spell_widget));
if (NULL != (child = gtk_bin_get_child (GTK_BIN (self->spell_revealer))))
{
gtk_container_remove (GTK_CONTAINER (self->spell_revealer), child);
self->spellchecker_opened = FALSE;
}
}
static void
update_replace_actions_sensitivity (IdeEditorFrame *self)
{
......@@ -845,6 +862,7 @@ ide_editor_frame__source_view_focus_in_event (IdeEditorFrame *self,
g_assert (IDE_IS_SOURCE_VIEW (source_view));
gtk_revealer_set_reveal_child (self->search_revealer, FALSE);
gtk_revealer_set_reveal_child (self->spell_revealer, FALSE);
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (source_view));
......@@ -1201,6 +1219,7 @@ ide_editor_frame_class_init (IdeEditorFrameClass *klass)
gtk_widget_class_bind_template_child (widget_class, IdeEditorFrame, replace_all_button);
gtk_widget_class_bind_template_child (widget_class, IdeEditorFrame, search_options);
gtk_widget_class_bind_template_child (widget_class, IdeEditorFrame, search_revealer);
gtk_widget_class_bind_template_child (widget_class, IdeEditorFrame, spell_revealer);
gtk_widget_class_bind_template_child (widget_class, IdeEditorFrame, source_map_container);
gtk_widget_class_bind_template_child (widget_class, IdeEditorFrame, source_overlay);
gtk_widget_class_bind_template_child (widget_class, IdeEditorFrame, source_view);
......
This diff is collapsed.
This diff is collapsed.
/* ide-editor-spell-widget.h
*
* Copyright (C) 2016 Sebastien Lafargue <slafargue@gnome.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef IDE_EDITOR_SPELL_WIDGET_H
#define IDE_EDITOR_SPELL_WIDGET_H
#include <glib-object.h>
#include <gtk/gtk.h>
#include "sourceview/ide-source-view.h"
G_BEGIN_DECLS
#define IDE_TYPE_EDITOR_SPELL_WIDGET (ide_editor_spell_widget_get_type())
G_DECLARE_FINAL_TYPE (IdeEditorSpellWidget, ide_editor_spell_widget, IDE, EDITOR_SPELL_WIDGET, GtkBin)
GtkWidget *ide_editor_spell_widget_new (IdeSourceView *source_view);
GtkWidget *ide_editor_spell_widget_get_entry (IdeEditorSpellWidget *self);
G_END_DECLS
#endif /* IDE_EDITOR_SPELL_WIDGET_H */
<
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.15 -->
<template class="IdeEditorSpellWidget" parent="GtkBin">
<child>
<object class="GtkFrame" id="spell_frame">
<property name="visible">true</property>
<property name="margin-end">12</property>
<style>
<class name="gb-spell-frame"/>
</style>
<child>
<object class="GtkBox">
<property name="visible">true</property>
<property name="orientation">vertical</property>
<property name="spacing">7</property>
<child>
<object class="GtkGrid">
<property name="visible">true</property>
<property name="row_spacing">6</property>
<property name="column_spacing">6</property>
<child>
<object class="GtkLabel">
<property name="visible">true</property>
<property name="label" translatable="yes">Misspelled</property>
<property name="halign">end</property>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">true</property>
<property name="label" translatable="yes">Change _to</property>
<property name="halign">end</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">word_entry</property>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">true</property>
<property name="label" translatable="yes">_Suggestions</property>
<property name="halign">end</property>
<property name="valign">start</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">suggestions_box</property>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">true</property>
<property name="orientation">horizontal</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel" id="word_label">
<property name="visible">true</property>
<property name="halign">start</property>
<property name="margin_left">10</property>
<property name="selectable">True</property>
<property name="use_markup">True</property>
<property name="wrap">True</property>
</object>
</child>
<child>
<object class="GtkLabel" id="count_label">
<property name="visible">true</property>
<property name="halign">end</property>
<property name="expand">true</property>
</object>
</child>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="word_entry">
<property name="visible">true</property>
<property name="can_focus">true</property>
<property name="width-chars">20</property>
<property name="max-width-chars">30</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="visible">true</property>
<property name="expand">true</property>
<property name="shadow_type">in</property>
<property name="min-content-height">110</property>
<property name="max-content-height">110</property>
<property name="propagate-natural-height">true</property>
<child>
<object class="GtkListBox" id="suggestions_box">
<property name="visible">true</property>
<property name="can_focus">true</property>
<property name="activate-on-single-click">false</property>
</object>
</child>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="add_dict_button">
<property name="label" translatable="yes">Add w_ord</property>
<property name="visible">true</property>
<property name="can_focus">true</property>
<property name="use_underline">True</property>
</object>
<packing>
<property name="left_attach">2</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="check_button">
<property name="label" translatable="yes">Check _word</property>
<property name="visible">true</property>
<property name="can_focus">true</property>
<property name="use_underline">True</property>
</object>
<packing>
<property name="left_attach">2</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="ignore_button">
<property name="label" translatable="yes">_Ignore</property>
<property name="visible">true</property>
<property name="can_focus">true</property>
<property name="use_underline">True</property>
</object>
<packing>
<property name="left_attach">3</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="change_button">
<property name="label" translatable="yes">Cha_nge</property>
<property name="visible">true</property>
<property name="can_focus">true</property>
<property name="use_underline">True</property>
</object>
<packing>
<property name="left_attach">3</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="ignore_all_button">
<property name="label" translatable="yes">Ignore _All</property>
<property name="visible">true</property>
<property name="can_focus">true</property>
<property name="use_underline">True</property>
</object>
<packing>
<property name="left_attach">4</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="change_all_button">
<property name="label" translatable="yes">Change A_ll</property>
<property name="visible">true</property>
<property name="can_focus">true</property>
<property name="use_underline">True</property>
</object>
<packing>
<property name="left_attach">4</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="close_button">
<property name="visible">true</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="focus_on_click">false</property>
<property name="action-name">spell-entry.exit-spell</property>
<style>
<class name="close"/>
</style>
<child>
<object class="GtkImage">
<property name="visible">true</property>
<property name="icon_name">window-close-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="left_attach">5</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkFrame" id="option_frame">
<property name="visible">true</property>
<property name="label" translatable="yes">Options</property>
<property name="shadow_type">in</property>
<property name="halign">fill</property>
<property name="valign">fill</property>
<child>
<object class="GtkGrid">
<property name="visible">true</property>
<property name="can_focus">false</property>
<property name="row_spacing">6</property>
<property name="column_spacing">6</property>
<property name="margin">6</property>
<child>
<object class="GtkLabel">
<property name="visible">true</property>
<property name="label" translatable="yes">_Language</property>
<property name="halign">end</property>
<property name="expand">true</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">language_chooser_button</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="highlight_checkbutton">
<property name="visible">true</property>
<property name="can_focus">true</property>
<property name="halign">end</property>
<property name="expand">true</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GspellLanguageChooserButton" id="language_chooser_button">
<property name="visible">true</property>
<property name="can_focus">true</property>
<property name="expand">true</property>
<property name="valign">center</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">true</property>
<property name="label" translatable="yes">_Highlight in the view</property>
<property name="expand">true</property>
<property name="halign">start</property>
<property name="margin-start">6</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">highlight_checkbutton</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
</object>
</child>