* Add a minimap

Add support for GtkSourceViews SourceMap object. Add both a default setting for
new files to the preferences dialog and a menu item to allow temporarily
disabling it in any view.

* Require gtk and gtksourceview 3.18

* load custom css

We can use this to make small tweaks to the interface so every theme doesn't
need to add specific support.

Make use of this new css to clean up the styling of the new overview map frame
a bit.
This commit is contained in:
JosephMcc 2017-09-25 07:01:27 -07:00 committed by Clement Lefebvre
parent 97e1b0a9ec
commit ce59112fd1
17 changed files with 241 additions and 35 deletions

View File

@ -149,8 +149,8 @@ PKG_CHECK_MODULES(XED, [
$GMODULE_ADD
gthread-2.0 >= 2.13.0
gio-2.0 >= 2.40.0
gtk+-3.0 >= 3.14.0
gtksourceview-3.0 >= 3.14.0
gtk+-3.0 >= 3.18.0
gtksourceview-3.0 >= 3.18.0
libpeas-1.0 >= 1.12.0
libpeas-gtk-1.0 >= 1.12.0
])

View File

@ -201,6 +201,12 @@
<description>Whether you can change active tabs by scrolling.</description>
</key>
<key name="minimap-visible" type="b">
<default>false</default>
<summary>Minimap is visible</summary>
<description>Whether the minimap for the document should be visible.</description>
</key>
<key name="max-recents" type="u">
<default>5</default>
<summary>Maximum Recent Files</summary>

View File

@ -0,0 +1,7 @@
.xed-map-frame:dir(ltr) {
border-width: 0 0 0 1px;
}
.xed-map-frame:dir(rtl) {
border-width: 0 1px 0 0;
}

View File

@ -545,6 +545,51 @@
<property name="position">4</property>
</packing>
</child>
<child>
<object class="GtkBox" id="box3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Overview Map</property>
<property name="xalign">0</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="mini_map_checkbutton">
<property name="label" translatable="yes">Display overview map</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="margin_left">12</property>
<property name="xalign">0</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">5</property>
</packing>
</child>
</object>
</child>
<child type="tab">

View File

@ -52,6 +52,7 @@
<menuitem name="ViewStatusbarMenu" action="ViewStatusbar"/>
<menuitem name="ViewSidePaneMenu" action="ViewSidePane"/>
<menuitem name="ViewBottomPaneMenu" action="ViewBottomPane"/>
<menuitem name="ViewOverviewMapMenu" action="ViewOverviewMap"/>
<separator/>
<menuitem name="ViewFullscreenMenu" action="ViewFullscreen"/>
<separator/>

View File

@ -7,16 +7,37 @@
<property name="has_focus">False</property>
<property name="is_focus">False</property>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow">
<object class="GtkGrid" id="grid">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="has_focus">False</property>
<property name="is_focus">False</property>
<property name="shadow_type">none</property>
<child>
<object class="XedView" id="view">
<object class="GtkScrolledWindow" id="scrolledwindow">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="has_focus">False</property>
<property name="is_focus">False</property>
<property name="shadow_type">none</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<child>
<object class="XedView" id="view">
<property name="visible">True</property>
<property name="can_focus">True</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkFrame" id="map_frame">
<property name="visible">True</property>
<style>
<class name="xed-map-frame"/>
</style>
<child>
<object class="GtkSourceMap" id="map">
<property name="visible">True</property>
<property name="view">view</property>
</object>
</child>
</object>
</child>
</object>

View File

@ -7,5 +7,6 @@
<file preprocess="xml-stripblanks">ui/xed-print-preferences.ui</file>
<file preprocess="xml-stripblanks">ui/xed-searchbar.ui</file>
<file preprocess="xml-stripblanks">ui/xed-view-frame.ui</file>
<file>css/xed-style.css</file>
</gresource>
</gresources>

View File

@ -234,6 +234,9 @@ xed_app_startup (GApplication *application)
const gchar *cache_dir;
gchar *metadata_filename;
#endif
GError *error = NULL;
GFile *css_file;
GtkCssProvider *provider;
G_APPLICATION_CLASS (xed_app_parent_class)->startup (application);
@ -259,36 +262,51 @@ xed_app_startup (GApplication *application)
g_free (metadata_filename);
#endif
/* Load settings */
app->priv->settings = xed_settings_new ();
app->priv->window_settings = g_settings_new ("org.x.editor.state.window");
app->priv->editor_settings = g_settings_new ("org.x.editor.preferences.editor");
/* Load settings */
app->priv->settings = xed_settings_new ();
app->priv->window_settings = g_settings_new ("org.x.editor.state.window");
app->priv->editor_settings = g_settings_new ("org.x.editor.preferences.editor");
set_initial_theme_style (app);
set_initial_theme_style (app);
/*
* We use the default gtksourceview style scheme manager so that plugins
* can obtain it easily without a xed specific api, but we need to
* add our search path at startup before the manager is actually used.
*/
manager = gtk_source_style_scheme_manager_get_default ();
gtk_source_style_scheme_manager_append_search_path (manager, xed_dirs_get_user_styles_dir ());
/* Load custom css */
css_file = g_file_new_for_uri ("resource:///org/x/editor/css/xed-style.css");
provider = gtk_css_provider_new ();
if (gtk_css_provider_load_from_file (provider, css_file, &error))
{
gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
GTK_STYLE_PROVIDER (provider),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
}
else
{
g_warning ("Could not load css provider: %s", error->message);
g_error_free (error);
}
app->priv->engine = xed_plugins_engine_get_default ();
app->priv->extensions = peas_extension_set_new (PEAS_ENGINE (app->priv->engine),
XED_TYPE_APP_ACTIVATABLE,
"app", app,
NULL);
/*
* We use the default gtksourceview style scheme manager so that plugins
* can obtain it easily without a xed specific api, but we need to
* add our search path at startup before the manager is actually used.
*/
manager = gtk_source_style_scheme_manager_get_default ();
gtk_source_style_scheme_manager_append_search_path (manager, xed_dirs_get_user_styles_dir ());
g_signal_connect (app->priv->extensions, "extension-added",
G_CALLBACK (extension_added), app);
app->priv->engine = xed_plugins_engine_get_default ();
app->priv->extensions = peas_extension_set_new (PEAS_ENGINE (app->priv->engine),
XED_TYPE_APP_ACTIVATABLE,
"app", app,
NULL);
g_signal_connect (app->priv->extensions, "extension-removed",
G_CALLBACK (extension_removed), app);
g_signal_connect (app->priv->extensions, "extension-added",
G_CALLBACK (extension_added), app);
peas_extension_set_foreach (app->priv->extensions,
(PeasExtensionSetForeachFunc) extension_added,
app);
g_signal_connect (app->priv->extensions, "extension-removed",
G_CALLBACK (extension_removed), app);
peas_extension_set_foreach (app->priv->extensions,
(PeasExtensionSetForeachFunc) extension_added,
app);
}
static gboolean

View File

@ -41,7 +41,7 @@
#include "xed-window.h"
#include "xed-window-private.h"
#include "xed-paned.h"
#include "xed-view-frame.h"
void
_xed_cmd_view_show_toolbar (GtkAction *action,
@ -144,6 +144,25 @@ _xed_cmd_view_show_bottom_pane (GtkAction *action,
}
}
void
_xed_cmd_view_toggle_overview_map (GtkAction *action,
XedWindow *window)
{
XedTab *tab;
XedViewFrame *frame;
GtkFrame *map_frame;
gboolean visible;
xed_debug (DEBUG_COMMANDS);
tab = xed_window_get_active_tab (window);
frame = XED_VIEW_FRAME (_xed_tab_get_view_frame (tab));
map_frame = xed_view_frame_get_map_frame (frame);
visible = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
gtk_widget_set_visible (GTK_WIDGET (map_frame), visible);
}
void
_xed_cmd_view_toggle_fullscreen_mode (GtkAction *action,
XedWindow *window)

View File

@ -45,6 +45,7 @@ void _xed_cmd_view_show_toolbar (GtkAction *action, XedWindow *window);
void _xed_cmd_view_show_statusbar (GtkAction *action, XedWindow *window);
void _xed_cmd_view_show_side_pane (GtkAction *action, XedWindow *window);
void _xed_cmd_view_show_bottom_pane (GtkAction *action, XedWindow *window);
void _xed_cmd_view_toggle_overview_map (GtkAction *action, XedWindow *window);
void _xed_cmd_view_toggle_fullscreen_mode (GtkAction *action, XedWindow *window);
void _xed_cmd_view_toggle_word_wrap (GtkAction *action, XedWindow *window);
void _xed_cmd_view_leave_fullscreen_mode (GtkAction *action, XedWindow *window);

View File

@ -123,6 +123,9 @@ struct _XedPreferencesDialogPrivate
/* Highlight matching bracket */
GtkWidget *bracket_matching_checkbutton;
/* Minimap */
GtkWidget *mini_map_checkbutton;
/* Right margin */
GtkWidget *right_margin_checkbutton;
GtkWidget *right_margin_position_spinbutton;
@ -355,6 +358,11 @@ setup_view_page (XedPreferencesDialog *dlg)
dlg->priv->right_margin_position_spinbutton,
"value",
G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
g_settings_bind (dlg->priv->ui,
XED_SETTINGS_MINIMAP_VISIBLE,
dlg->priv->mini_map_checkbutton,
"active",
G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
g_signal_connect (dlg->priv->wrap_text_checkbutton, "toggled",
G_CALLBACK (wrap_mode_checkbutton_toggled), dlg);
g_signal_connect (dlg->priv->split_checkbutton, "toggled",
@ -1121,6 +1129,7 @@ xed_preferences_dialog_init (XedPreferencesDialog *dlg)
dlg->priv->display_line_numbers_checkbutton = GTK_WIDGET (gtk_builder_get_object (builder, "display_line_numbers_checkbutton"));
dlg->priv->highlight_current_line_checkbutton = GTK_WIDGET (gtk_builder_get_object (builder, "highlight_current_line_checkbutton"));
dlg->priv->bracket_matching_checkbutton = GTK_WIDGET (gtk_builder_get_object (builder, "bracket_matching_checkbutton"));
dlg->priv->mini_map_checkbutton = GTK_WIDGET (gtk_builder_get_object (builder, "mini_map_checkbutton"));
dlg->priv->wrap_text_checkbutton = GTK_WIDGET (gtk_builder_get_object (builder, "wrap_text_checkbutton"));
dlg->priv->split_checkbutton = GTK_WIDGET (gtk_builder_get_object (builder, "split_checkbutton"));
dlg->priv->right_margin_checkbutton = GTK_WIDGET (gtk_builder_get_object (builder, "right_margin_checkbutton"));

View File

@ -98,6 +98,7 @@ void xed_settings_set_list (GSettings *settings,
#define XED_SETTINGS_STATUSBAR_VISIBLE "statusbar-visible"
#define XED_SETTINGS_SIDE_PANEL_VISIBLE "side-panel-visible"
#define XED_SETTINGS_BOTTOM_PANEL_VISIBLE "bottom-panel-visible"
#define XED_SETTINGS_MINIMAP_VISIBLE "minimap-visible"
#define XED_SETTINGS_MAX_RECENTS "max-recents"
#define XED_SETTINGS_PRINT_SYNTAX_HIGHLIGHTING "print-syntax-highlighting"
#define XED_SETTINGS_PRINT_HEADER "print-header"

View File

@ -159,7 +159,10 @@ static const GtkToggleActionEntry xed_always_sensitive_toggle_menu_entries[] =
G_CALLBACK (_xed_cmd_view_toggle_fullscreen_mode), FALSE },
{ "ViewWordWrap", NULL, N_("_Word wrap"), NULL,
N_("Set word wrap for the current document"),
G_CALLBACK (_xed_cmd_view_toggle_word_wrap), FALSE }
G_CALLBACK (_xed_cmd_view_toggle_word_wrap), FALSE },
{ "ViewOverviewMap", NULL, N_("_Overview Map"), NULL,
N_("Show or hide the overview map for the current view"),
G_CALLBACK (_xed_cmd_view_toggle_overview_map), FALSE }
};
/* separate group, should be always sensitive except when there are no panes */

View File

@ -28,6 +28,7 @@
#include "xed-marshal.h"
#include "xed-debug.h"
#include "xed-utils.h"
#include "xed-settings.h"
#include <gdk/gdkkeysyms.h>
#include <glib/gi18n.h>
@ -40,6 +41,10 @@
struct _XedViewFramePrivate
{
GtkWidget *view;
GtkFrame *map_frame;
GtkSourceMap *map;
GSettings *ui_settings;
GtkTextMark *start_mark;
@ -96,6 +101,8 @@ xed_view_frame_dispose (GObject *object)
gtk_source_file_set_mount_operation_factory (file, NULL, NULL, NULL);
}
g_clear_object (&frame->priv->ui_settings);
G_OBJECT_CLASS (xed_view_frame_parent_class)->dispose (object);
}
@ -499,6 +506,8 @@ xed_view_frame_class_init (XedViewFrameClass *klass)
gtk_widget_class_set_template_from_resource (widget_class, "/org/x/editor/ui/xed-view-frame.ui");
gtk_widget_class_bind_template_child_private (widget_class, XedViewFrame, view);
gtk_widget_class_bind_template_child_private (widget_class, XedViewFrame, map_frame);
gtk_widget_class_bind_template_child_private (widget_class, XedViewFrame, map);
gtk_widget_class_bind_template_child_private (widget_class, XedViewFrame, revealer);
gtk_widget_class_bind_template_child_private (widget_class, XedViewFrame, search_entry);
}
@ -519,11 +528,23 @@ xed_view_frame_init (XedViewFrame *frame)
XedDocument *doc;
GtkSourceFile *file;
GdkRGBA transparent = {0, 0, 0, 0};
PangoFontDescription *font_desc;
frame->priv = xed_view_frame_get_instance_private (frame);
gtk_widget_init_template (GTK_WIDGET (frame));
frame->priv->ui_settings = g_settings_new ("org.x.editor.preferences.ui");
g_settings_bind (frame->priv->ui_settings,
XED_SETTINGS_MINIMAP_VISIBLE,
frame->priv->map_frame,
"visible",
G_SETTINGS_BIND_GET | G_SETTINGS_BIND_NO_SENSITIVITY);
font_desc = pango_font_description_from_string ("Monospace 2");
g_object_set (frame->priv->map, "font-desc", font_desc, NULL);
pango_font_description_free (font_desc);
gtk_widget_override_background_color (GTK_WIDGET (frame), 0, &transparent);
doc = xed_view_frame_get_document (frame);
@ -559,6 +580,14 @@ xed_view_frame_get_view (XedViewFrame *frame)
return XED_VIEW (frame->priv->view);
}
GtkFrame *
xed_view_frame_get_map_frame (XedViewFrame *frame)
{
g_return_val_if_fail (XED_IS_VIEW_FRAME (frame), NULL);
return frame->priv->map_frame;
}
void
xed_view_frame_popup_goto_line (XedViewFrame *frame)
{

View File

@ -61,6 +61,8 @@ XedDocument *xed_view_frame_get_document (XedViewFrame *frame);
XedView *xed_view_frame_get_view (XedViewFrame *frame);
GtkFrame *xed_view_frame_get_map_frame (XedViewFrame *frame);
void xed_view_frame_popup_goto_line (XedViewFrame *frame);
gboolean xed_view_frame_get_search_popup_visible (XedViewFrame *frame);

View File

@ -79,6 +79,7 @@ struct _XedWindowPrivate
guint spaces_instead_of_tabs_id;
guint language_changed_id;
guint use_word_wrap_id;
guint show_overview_map_id;
/* Menus & Toolbars */
GtkUIManager *manager;

View File

@ -2170,6 +2170,28 @@ word_wrap_changed (GObject *object,
g_signal_handlers_unblock_by_func (action, G_CALLBACK (_xed_cmd_view_toggle_word_wrap), window);
}
static void
show_overview_map_changed (GObject *object,
GParamSpec *pspec,
XedWindow *window)
{
GtkFrame *map_frame;
GtkAction *action;
gboolean overveiw_map_visible = FALSE;
map_frame = GTK_FRAME (object);
action = gtk_action_group_get_action (window->priv->always_sensitive_action_group, "ViewOverviewMap");
if (gtk_widget_get_visible (map_frame))
{
overveiw_map_visible = TRUE;
}
g_signal_handlers_block_by_func (action, G_CALLBACK (_xed_cmd_view_toggle_overview_map), window);
gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), overveiw_map_visible);
g_signal_handlers_unblock_by_func (action, G_CALLBACK (_xed_cmd_view_toggle_overview_map), window);
}
static void
notebook_switch_page (GtkNotebook *book,
GtkWidget *pg,
@ -2177,6 +2199,7 @@ notebook_switch_page (GtkNotebook *book,
XedWindow *window)
{
XedView *view;
GtkFrame *map_frame;
XedTab *tab;
GtkAction *action;
gchar *action_name;
@ -2184,7 +2207,7 @@ notebook_switch_page (GtkNotebook *book,
/* CHECK: I don't know why but it seems notebook_switch_page is called
two times every time the user change the active tab */
tab = XED_TAB(gtk_notebook_get_nth_page (book, page_num));
tab = XED_TAB (gtk_notebook_get_nth_page (book, page_num));
if (tab == window->priv->active_tab)
{
return;
@ -2209,6 +2232,12 @@ notebook_switch_page (GtkNotebook *book,
g_signal_handler_disconnect (xed_tab_get_view (window->priv->active_tab), window->priv->use_word_wrap_id);
window->priv->use_word_wrap_id = 0;
}
if (window->priv->show_overview_map_id)
{
g_signal_handler_disconnect (xed_view_frame_get_map_frame (_xed_tab_get_view_frame (window->priv->active_tab)), window->priv->show_overview_map_id);
window->priv->show_overview_map_id = 0;
}
}
/* set the active tab */
@ -2236,6 +2265,7 @@ notebook_switch_page (GtkNotebook *book,
update_languages_menu (window);
view = xed_tab_get_view (tab);
map_frame = xed_view_frame_get_map_frame (_xed_tab_get_view_frame (tab));
/* sync the statusbar */
update_cursor_position_statusbar (GTK_TEXT_BUFFER (xed_tab_get_document (tab)), window);
@ -2256,11 +2286,15 @@ notebook_switch_page (GtkNotebook *book,
window->priv->use_word_wrap_id = g_signal_connect (view, "notify::wrap-mode",
G_CALLBACK (word_wrap_changed), window);
window->priv->show_overview_map_id = g_signal_connect (map_frame, "notify::visible",
G_CALLBACK (show_overview_map_changed), window);
/* call it for the first time */
tab_width_changed (G_OBJECT (view), NULL, window);
spaces_instead_of_tabs_changed (G_OBJECT (view), NULL, window);
language_changed (G_OBJECT (xed_tab_get_document (tab)), NULL, window);
word_wrap_changed (G_OBJECT (view), NULL, window);
show_overview_map_changed (G_OBJECT (map_frame), NULL, window);
g_signal_emit (G_OBJECT (window), signals[ACTIVE_TAB_CHANGED], 0, window->priv->active_tab);
}
@ -3025,6 +3059,7 @@ notebook_tab_removed (XedNotebook *notebook,
XedWindow *window)
{
XedView *view;
XedViewFrame *frame;
XedDocument *doc;
xed_debug (DEBUG_WINDOW);
@ -3034,6 +3069,7 @@ notebook_tab_removed (XedNotebook *notebook,
--window->priv->num_tabs;
view = xed_tab_get_view (tab);
frame = _xed_tab_get_view_frame (tab);
doc = xed_tab_get_document (tab);
g_signal_handlers_disconnect_by_func (tab, G_CALLBACK (sync_name), window);
@ -3074,6 +3110,12 @@ notebook_tab_removed (XedNotebook *notebook,
window->priv->use_word_wrap_id = 0;
}
if (window->priv->show_overview_map_id && tab == xed_window_get_active_tab (window))
{
g_signal_handler_disconnect (xed_view_frame_get_map_frame (frame), window->priv->show_overview_map_id);
window->priv->show_overview_map_id = 0;
}
g_return_if_fail(window->priv->num_tabs >= 0);
if (window->priv->num_tabs == 0)
{