diff --git a/configure.ac b/configure.ac index 4a86719..2ca807b 100644 --- a/configure.ac +++ b/configure.ac @@ -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 ]) diff --git a/data/org.x.editor.gschema.xml.in b/data/org.x.editor.gschema.xml.in index 84e5d2a..ebaf070 100644 --- a/data/org.x.editor.gschema.xml.in +++ b/data/org.x.editor.gschema.xml.in @@ -201,6 +201,12 @@ Whether you can change active tabs by scrolling. + + false + Minimap is visible + Whether the minimap for the document should be visible. + + 5 Maximum Recent Files diff --git a/xed/resources/css/xed-style.css b/xed/resources/css/xed-style.css new file mode 100644 index 0000000..984ca8a --- /dev/null +++ b/xed/resources/css/xed-style.css @@ -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; +} \ No newline at end of file diff --git a/xed/resources/ui/xed-preferences-dialog.ui b/xed/resources/ui/xed-preferences-dialog.ui index 7194dd4..5975d36 100755 --- a/xed/resources/ui/xed-preferences-dialog.ui +++ b/xed/resources/ui/xed-preferences-dialog.ui @@ -545,6 +545,51 @@ 4 + + + True + False + vertical + 6 + + + True + False + Overview Map + 0 + + + + + + False + True + 0 + + + + + Display overview map + True + True + False + 12 + 0 + True + + + False + True + 1 + + + + + True + True + 5 + + diff --git a/xed/resources/ui/xed-ui.xml b/xed/resources/ui/xed-ui.xml index 4da5c7a..10d48bf 100644 --- a/xed/resources/ui/xed-ui.xml +++ b/xed/resources/ui/xed-ui.xml @@ -52,6 +52,7 @@ + diff --git a/xed/resources/ui/xed-view-frame.ui b/xed/resources/ui/xed-view-frame.ui index 81fe13e..af7efa0 100644 --- a/xed/resources/ui/xed-view-frame.ui +++ b/xed/resources/ui/xed-view-frame.ui @@ -7,16 +7,37 @@ False False - + True - True - False - False - none - + True True + False + False + none + True + True + + + True + True + + + + + + + True + + + + True + view + + diff --git a/xed/resources/xed.gresource.xml b/xed/resources/xed.gresource.xml index f960a0d..b02bde6 100644 --- a/xed/resources/xed.gresource.xml +++ b/xed/resources/xed.gresource.xml @@ -7,5 +7,6 @@ ui/xed-print-preferences.ui ui/xed-searchbar.ui ui/xed-view-frame.ui + css/xed-style.css \ No newline at end of file diff --git a/xed/xed-app.c b/xed/xed-app.c index 1ecc587..785e162 100644 --- a/xed/xed-app.c +++ b/xed/xed-app.c @@ -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 diff --git a/xed/xed-commands-view.c b/xed/xed-commands-view.c index a09b401..f692e55 100644 --- a/xed/xed-commands-view.c +++ b/xed/xed-commands-view.c @@ -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) diff --git a/xed/xed-commands.h b/xed/xed-commands.h index 1977ddc..1ff5ae9 100644 --- a/xed/xed-commands.h +++ b/xed/xed-commands.h @@ -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); diff --git a/xed/xed-preferences-dialog.c b/xed/xed-preferences-dialog.c index 79efe1d..2e3ad43 100755 --- a/xed/xed-preferences-dialog.c +++ b/xed/xed-preferences-dialog.c @@ -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")); diff --git a/xed/xed-settings.h b/xed/xed-settings.h index f65c01f..9114a33 100644 --- a/xed/xed-settings.h +++ b/xed/xed-settings.h @@ -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" diff --git a/xed/xed-ui.h b/xed/xed-ui.h index acefb5e..24e97b5 100644 --- a/xed/xed-ui.h +++ b/xed/xed-ui.h @@ -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 */ diff --git a/xed/xed-view-frame.c b/xed/xed-view-frame.c index eba0299..7db49f0 100644 --- a/xed/xed-view-frame.c +++ b/xed/xed-view-frame.c @@ -28,6 +28,7 @@ #include "xed-marshal.h" #include "xed-debug.h" #include "xed-utils.h" +#include "xed-settings.h" #include #include @@ -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) { diff --git a/xed/xed-view-frame.h b/xed/xed-view-frame.h index 1cb6d12..6e1c7fe 100644 --- a/xed/xed-view-frame.h +++ b/xed/xed-view-frame.h @@ -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); diff --git a/xed/xed-window-private.h b/xed/xed-window-private.h index c7ec07a..2e3b5c1 100644 --- a/xed/xed-window-private.h +++ b/xed/xed-window-private.h @@ -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; diff --git a/xed/xed-window.c b/xed/xed-window.c index 7a7496d..9d8e369 100644 --- a/xed/xed-window.c +++ b/xed/xed-window.c @@ -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) {