Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
280 changes: 135 additions & 145 deletions src/Widgets/FormatBar.vala
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,16 @@
public class Code.FormatBar : Gtk.Box {
public bool tab_style_set_by_editor_config { get; set; default = false; }
public bool tab_width_set_by_editor_config { get; set; default = false; }
public Gtk.InfoBar editorconfig_infobar { get; set construct; }
public Gtk.Box tab_box { get; set construct; }
public Gtk.SpinButton width_spinbutton { get; set construct; }

private FormatButton line_menubutton;
private FormatButton lang_menubutton;
private FormatButton tab_menubutton;
private Granite.SwitchModelButton space_tab_modelbutton;
private Gtk.Entry goto_entry;
private Gtk.InfoBar editorconfig_infobar;
private Gtk.ListBox lang_selection_listbox;
private Gtk.SearchEntry lang_selection_filter;
private Gtk.SourceLanguageManager manager;
private Gtk.SpinButton width_spinbutton;
private LangEntry normal_entry;

private unowned Scratch.Services.Document? doc = null;
Expand All @@ -41,159 +39,155 @@ public class Code.FormatBar : Gtk.Box {

manager = Gtk.SourceLanguageManager.get_default ();

tab_menubutton = new FormatButton () {
icon = new ThemedIcon ("format-indent-more-symbolic")
editorconfig_infobar = new Gtk.InfoBar () {
margin_top = 9,
margin_end = 9,
margin_start = 9
};
editorconfig_infobar.get_content_area ().add (new Gtk.Label (_("Some settings set by EditorConfig file")));
editorconfig_infobar.get_style_context ().add_class (Gtk.STYLE_CLASS_FRAME);

lang_menubutton = new FormatButton () {
icon = new ThemedIcon ("application-x-class-file-symbolic"),
tooltip_text = _("Document language")
};
var autoindent_modelbutton = new Granite.SwitchModelButton (_("Automatic Indentation"));

line_menubutton = new FormatButton () {
icon = new ThemedIcon ("view-continuous-symbolic")
space_tab_modelbutton = new Granite.SwitchModelButton (_("Insert Spaces Instead Of Tabs"));

width_spinbutton = new Gtk.SpinButton.with_range (2, 16, 1);

var width_label = new Gtk.Label (_("Tab width")) {
halign = START,
hexpand = true,
mnemonic_widget = width_spinbutton
};
line_menubutton.tooltip_markup = Granite.markup_accel_tooltip (
((Scratch.Application) GLib.Application.get_default ()).get_accels_for_action (
Scratch.MainWindow.ACTION_PREFIX + Scratch.MainWindow.ACTION_GO_TO
),
_("Line number")
);

homogeneous = true;
add (tab_menubutton);
add (lang_menubutton);
add (line_menubutton);
var tab_box = new Gtk.Box (HORIZONTAL, 12) {
margin_top = 6,
margin_end = 12,
margin_start = 12,
};
tab_box.add (width_label);
tab_box.add (width_spinbutton);

create_tabulation_popover ();
create_language_popover ();
create_line_popover ();
}
var box = new Gtk.Box (VERTICAL, 0) {
margin_bottom = 12
};
box.add (editorconfig_infobar);
box.add (autoindent_modelbutton);
box.add (space_tab_modelbutton);
box.add (tab_box);
box.show_all ();

public void activate_line_menubutton () {
line_menubutton.active = true;
}
var tab_popover = new Gtk.Popover (null) {
position = BOTTOM,
child = box
};

private void create_language_popover () {
lang_selection_listbox = new Gtk.ListBox ();
lang_selection_listbox.selection_mode = Gtk.SelectionMode.SINGLE;
lang_selection_listbox.set_sort_func ((row1, row2) => {
return ((LangEntry) row1).lang_name.collate (((LangEntry) row2).lang_name);
});
lang_selection_listbox.set_filter_func ((row) => {
//Both are lowercased so that the case doesn't matter when comparing.
return (((LangEntry) row).lang_name.down ().contains (lang_selection_filter.text.down ().strip ()));
});
tab_menubutton = new FormatButton () {
icon = new ThemedIcon ("format-indent-more-symbolic"),
popover = tab_popover
};

lang_selection_filter = new Gtk.SearchEntry () {
var lang_selection_filter = new Gtk.SearchEntry () {
margin_top = 12,
margin_bottom = 6,
margin_start = 12,
margin_end = 12,
placeholder_text = _("Filter languages")
};

lang_selection_filter.changed.connect (() => {
lang_selection_listbox.invalidate_filter ();
});

var lang_scrolled = new Gtk.ScrolledWindow (null, null) {
hscrollbar_policy = Gtk.PolicyType.NEVER,
height_request = 350,
hexpand = true,
vexpand = true,
margin_top = 3,
margin_bottom = 3,
child = lang_selection_listbox
lang_selection_listbox = new Gtk.ListBox () {
selection_mode = SINGLE
};
lang_selection_listbox.set_sort_func ((row1, row2) => {
return ((LangEntry) row1).lang_name.collate (((LangEntry) row2).lang_name);
});
lang_selection_listbox.set_filter_func ((row) => {
//Both are lowercased so that the case doesn't matter when comparing.
return (((LangEntry) row).lang_name.down ().contains (lang_selection_filter.text.down ().strip ()));
});

unowned string[]? ids = manager.get_language_ids ();
unowned SList<Gtk.RadioButton> group = null;
foreach (unowned string id in ids) {
foreach (unowned string id in manager.get_language_ids ()) {
weak Gtk.SourceLanguage lang = manager.get_language (id);
var entry = new LangEntry (id, lang.name, group);
group = entry.get_radio_group ();
lang_selection_listbox.add (entry);
}

normal_entry = new LangEntry (null, _("Plain Text"), group);

lang_selection_listbox.add (normal_entry);

var popover_content = new Gtk.Box (Gtk.Orientation.VERTICAL, 0);
var lang_scrolled = new Gtk.ScrolledWindow (null, null) {
child = lang_selection_listbox,
hscrollbar_policy = NEVER,
height_request = 350,
hexpand = true,
vexpand = true,
margin_top = 3,
margin_bottom = 3
};

var popover_content = new Gtk.Box (VERTICAL, 0);
popover_content.add (lang_selection_filter);
popover_content.add (lang_scrolled);

popover_content.show_all ();

var lang_popover = new Gtk.Popover (lang_menubutton) {
position = Gtk.PositionType.BOTTOM,
var lang_popover = new Gtk.Popover (null) {
position = BOTTOM,
child = popover_content
};
lang_menubutton.popover = lang_popover;

lang_selection_listbox.row_activated.connect ((row) => {
var lang_entry = ((LangEntry) row);
select_language (lang_entry);
});
}

private void select_language (LangEntry lang, bool update_source_view = true) {
lang_selection_listbox.select_row (lang);
lang_menubutton.text = lang.lang_name;
if (update_source_view) {
lang.active = true;
doc.source_view.language = lang.lang_id != null ? manager.get_language (lang.lang_id) : null;
} else {
lang.selected = true;
}
}

private void create_tabulation_popover () {
editorconfig_infobar = new Gtk.InfoBar () {
margin_top = 9,
margin_end = 9,
margin_start = 9
lang_menubutton = new FormatButton () {
icon = new ThemedIcon ("application-x-class-file-symbolic"),
popover = lang_popover,
tooltip_text = _("Document language")
};
editorconfig_infobar.get_content_area ().add (new Gtk.Label (_("Some settings set by EditorConfig file")));
editorconfig_infobar.get_style_context ().add_class (Gtk.STYLE_CLASS_FRAME);

var autoindent_modelbutton = new Granite.SwitchModelButton (_("Automatic Indentation"));

space_tab_modelbutton = new Granite.SwitchModelButton (_("Insert Spaces Instead Of Tabs"));
goto_entry = new Gtk.Entry ();

var width_label = new Gtk.Label (_("Tab width")) {
halign = Gtk.Align.START,
hexpand = true
var goto_label = new Gtk.Label (_("Go To Line:")) {
mnemonic_widget = goto_entry
};

width_spinbutton = new Gtk.SpinButton.with_range (2, 16, 1);

tab_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 12) {
margin_top = 6,
margin_end = 12,
var line_box = new Gtk.Box (HORIZONTAL, 12) {
margin_top = 12,
margin_bottom = 12,
margin_start = 12,
margin_end = 12
};
tab_box.add (width_label);
tab_box.add (width_spinbutton);
line_box.add (goto_label);
line_box.add (goto_entry);
line_box.show_all ();

var box = new Gtk.Box (Gtk.Orientation.VERTICAL, 0) {
margin_bottom = 12
var line_popover = new Gtk.Popover (null) {
position = BOTTOM,
child = line_box
};
box.add (editorconfig_infobar);
box.add (autoindent_modelbutton);
box.add (space_tab_modelbutton);
box.add (tab_box);
box.show_all ();

var tab_popover = new Gtk.Popover (tab_menubutton) {
position = Gtk.PositionType.BOTTOM,
child = box
line_menubutton = new FormatButton () {
icon = new ThemedIcon ("view-continuous-symbolic"),
popover = line_popover
};
tab_menubutton.popover = tab_popover;
line_menubutton.tooltip_markup = Granite.markup_accel_tooltip (
((Scratch.Application) GLib.Application.get_default ()).get_accels_for_action (
Scratch.MainWindow.ACTION_PREFIX + Scratch.MainWindow.ACTION_GO_TO
),
_("Line number")
);

Scratch.settings.changed["indent-width"].connect (format_tab_header_from_global_settings);
Scratch.settings.changed["spaces-instead-of-tabs"].connect (format_tab_header_from_global_settings);
Scratch.settings.bind ("auto-indent", autoindent_modelbutton, "active", SettingsBindFlags.DEFAULT);
homogeneous = true;
add (tab_menubutton);
add (lang_menubutton);
add (line_menubutton);

lang_selection_listbox.row_activated.connect ((row) => {
var lang_entry = ((LangEntry) row);
select_language (lang_entry);
});

lang_selection_filter.changed.connect (() => {
lang_selection_listbox.invalidate_filter ();
});

format_tab_header_from_global_settings ();
width_spinbutton.value_changed.connect (() => {
Expand All @@ -213,6 +207,37 @@ public class Code.FormatBar : Gtk.Box {
);
}
});

// We need to connect_after because otherwise, the text isn't parsed into the "value" property and we only get the previous value
goto_entry.activate.connect_after (() => {
int line, column;
goto_entry.text = goto_entry.text.replace (":", ".");
goto_entry.text.scanf ("%i.%i", out line, out column);
doc.source_view.go_to_line (line, column - 1);
// Focuses parent to the source view, so that the cursor, which indicates line and column is actually visible.
doc.source_view.grab_focus ();
});

Scratch.settings.changed["indent-width"].connect (format_tab_header_from_global_settings);
Scratch.settings.changed["spaces-instead-of-tabs"].connect (format_tab_header_from_global_settings);
Scratch.settings.bind ("auto-indent", autoindent_modelbutton, "active", DEFAULT);

bind_property ("tab-width-set-by-editor-config", tab_box, "sensitive", INVERT_BOOLEAN | SYNC_CREATE);
}

public void activate_line_menubutton () {
line_menubutton.active = true;
}

private void select_language (LangEntry lang, bool update_source_view = true) {
lang_selection_listbox.select_row (lang);
lang_menubutton.text = lang.lang_name;
if (update_source_view) {
lang.active = true;
doc.source_view.language = lang.lang_id != null ? manager.get_language (lang.lang_id) : null;
} else {
lang.selected = true;
}
}

private void format_tab_header_from_global_settings () {
Expand All @@ -226,7 +251,6 @@ public class Code.FormatBar : Gtk.Box {

editorconfig_infobar.revealed = tab_style_set_by_editor_config || tab_width_set_by_editor_config;
space_tab_modelbutton.sensitive = !tab_style_set_by_editor_config;
tab_box.sensitive = !tab_width_set_by_editor_config;
}

private void format_line_header () {
Expand All @@ -239,40 +263,6 @@ public class Code.FormatBar : Gtk.Box {
goto_entry.text = "%d.%d".printf (line, iter.get_line_offset () + 1);
}

private void create_line_popover () {
var goto_label = new Gtk.Label (_("Go To Line:"));
goto_label.xalign = 1;

goto_entry = new Gtk.Entry ();

var line_grid = new Gtk.Grid () {
margin_top = 12,
margin_bottom = 12,
margin_start = 12,
margin_end = 12
};
line_grid.column_spacing = 12;
line_grid.attach (goto_label, 0, 0, 1, 1);
line_grid.attach (goto_entry, 1, 0, 1, 1);
line_grid.show_all ();

var line_popover = new Gtk.Popover (line_menubutton) {
position = Gtk.PositionType.BOTTOM,
child = line_grid
};
line_menubutton.popover = line_popover;

// We need to connect_after because otherwise, the text isn't parsed into the "value" property and we only get the previous value
goto_entry.activate.connect_after (() => {
int line, column;
goto_entry.text = goto_entry.text.replace (":", ".");
goto_entry.text.scanf ("%i.%i", out line, out column);
doc.source_view.go_to_line (line, column - 1);
// Focuses parent to the source view, so that the cursor, which indicates line and column is actually visible.
doc.source_view.grab_focus ();
});
}

public void set_document (Scratch.Services.Document doc) {
if (this.doc != null) {
this.doc.source_view.buffer.notify["cursor-position"].disconnect (format_line_header);
Expand Down