162
static gchar *statusbar_template = NULL;
164
/* note: some comments below are for translators */
165
static void add_statusbar_statistics(GString *stats_str,
166
GeanyDocument *doc, guint line, guint col)
168
const gchar *cur_tag;
170
const gchar *expos; /* % expansion position */
171
const gchar sp[] = " ";
173
fmt = NZV(statusbar_template) ? statusbar_template :
174
/* Status bar statistics: col = column, sel = selection. */
175
_("line: %l / %L\t col: %c\t sel: %s\t %w %t %m"
176
"mode: %M encoding: %e filetype: %f scope: %S");
178
g_string_assign(stats_str, "");
179
while ((expos = strchr(fmt, '%')) != NULL)
181
/* append leading text before % char */
182
g_string_append_len(stats_str, fmt, expos - fmt);
187
g_string_append_printf(stats_str, "%d", line + 1);
190
g_string_append_printf(stats_str, "%d",
191
sci_get_line_count(doc->editor->sci));
194
g_string_append_printf(stats_str, "%d", col);
197
g_string_append_printf(stats_str, "%d", col + 1);
200
g_string_append_printf(stats_str, "%d",
201
sci_get_selected_text_length(doc->editor->sci) - 1);
205
g_string_append(stats_str, (doc->readonly) ? _("RO ") :
206
/* OVR = overwrite/overtype, INS = insert */
207
(sci_get_overtype(doc->editor->sci) ? _("OVR") : _("INS")));
212
g_string_append(stats_str, _("RO ")); /* RO = read-only */
213
g_string_append(stats_str, sp + 1);
218
switch (editor_get_indent_prefs(doc->editor)->type)
220
case GEANY_INDENT_TYPE_TABS:
221
g_string_append(stats_str, _("TAB"));
223
case GEANY_INDENT_TYPE_SPACES: /* SP = space */
224
g_string_append(stats_str, _("SP"));
226
case GEANY_INDENT_TYPE_BOTH: /* T/S = tabs and spaces */
227
g_string_append(stats_str, _("T/S"));
235
g_string_append(stats_str, _("MOD")); /* MOD = modified */
236
g_string_append(stats_str, sp);
240
g_string_append(stats_str, editor_get_eol_char_name(doc->editor));
243
g_string_append(stats_str,
244
doc->encoding ? doc->encoding : _("unknown"));
245
if (encodings_is_unicode_charset(doc->encoding) && (doc->has_bom))
247
g_string_append_c(stats_str, ' ');
248
g_string_append(stats_str, _("(with BOM)")); /* BOM = byte order mark */
252
g_string_append(stats_str, filetypes_get_display_name(doc->file_type));
255
symbols_get_current_function(doc, &cur_tag);
256
g_string_append(stats_str, cur_tag);
259
g_string_append_len(stats_str, expos, 1);
262
/* skip past %c chars */
268
/* add any remaining text */
269
g_string_append(stats_str, fmt);
161
273
/* updates the status bar document statistics */
162
274
void ui_update_statusbar(GeanyDocument *doc, gint pos)
193
/* Status bar statistics: col = column, sel = selection. */
194
g_string_printf(stats_str, _("line: %d / %d\t col: %d\t sel: %d\t "),
195
(line + 1), sci_get_line_count(doc->editor->sci), col,
196
sci_get_selected_text_length(doc->editor->sci) - 1);
198
g_string_append(stats_str,
200
(doc->readonly) ? _("RO ") :
201
/* OVR = overwrite/overtype, INS = insert */
202
(sci_get_overtype(doc->editor->sci) ? _("OVR") : _("INS")));
203
g_string_append(stats_str, sp);
205
switch (editor_get_indent_prefs(doc->editor)->type)
207
case GEANY_INDENT_TYPE_TABS:
208
g_string_append(stats_str, _("TAB"));
210
case GEANY_INDENT_TYPE_SPACES:
211
g_string_append(stats_str, _("SP")); /* SP = space */
213
case GEANY_INDENT_TYPE_BOTH:
214
g_string_append(stats_str, _("T/S")); /* T/S = tabs and spaces */
217
g_string_append(stats_str, sp);
218
g_string_append_printf(stats_str, _("mode: %s"),
219
editor_get_eol_char_name(doc->editor));
220
g_string_append(stats_str, sp);
221
g_string_append_printf(stats_str, _("encoding: %s %s"),
222
(doc->encoding) ? doc->encoding : _("unknown"),
223
(encodings_is_unicode_charset(doc->encoding)) ?
224
/* BOM = byte order mark */
225
((doc->has_bom) ? _("(with BOM)") : "") : "");
226
g_string_append(stats_str, sp);
227
g_string_append_printf(stats_str, _("filetype: %s"), filetype_name);
228
g_string_append(stats_str, sp);
231
g_string_append(stats_str, _("MOD")); /* MOD = modified */
232
g_string_append(stats_str, sp);
235
symbols_get_current_function(doc, &cur_tag);
236
g_string_append_printf(stats_str, _("scope: %s"),
302
add_statusbar_statistics(stats_str, doc, line, col);
239
304
#ifdef GEANY_DEBUG
306
const gchar sp[] = " ";
240
307
g_string_append(stats_str, sp);
241
308
g_string_append_printf(stats_str, "pos: %d", pos);
242
309
g_string_append(stats_str, sp);
243
310
g_string_append_printf(stats_str, "style: %d", sci_get_style_at(doc->editor->sci, pos));
246
313
/* can be overridden by status messages */
247
314
set_statusbar(stats_str->str, TRUE);
572
643
gtk_container_add(GTK_CONTAINER(menu_edit), item);
573
644
gtk_widget_show(item);
574
645
g_signal_connect(item, "activate", G_CALLBACK(on_menu_insert_date_activate), str);
575
g_object_set_data_full(G_OBJECT(main_widgets.window),
576
"insert_date_custom1", g_object_ref(item), (GDestroyNotify)g_object_unref);
646
ui_hookup_widget(main_widgets.window, item, "insert_date_custom1");
578
648
item = gtk_menu_item_new_with_mnemonic(str);
579
649
gtk_container_add(GTK_CONTAINER(menu_popup), item);
580
650
gtk_widget_show(item);
581
651
g_signal_connect(item, "activate", G_CALLBACK(on_insert_date_activate), str);
582
g_object_set_data_full(G_OBJECT(main_widgets.editor_menu),
583
"insert_date_custom2", g_object_ref(item), (GDestroyNotify)g_object_unref);
652
ui_hookup_widget(main_widgets.editor_menu, item, "insert_date_custom2");
585
654
insert_date_items(menu_edit, menu_popup, _("_Set Custom Date Format"));
661
730
add_doc_widget("replace1");
662
731
add_doc_widget("find_nextsel1");
663
732
add_doc_widget("find_prevsel1");
733
add_doc_widget("find_usage1");
734
add_doc_widget("find_document_usage1");
664
735
add_doc_widget("go_to_line1");
736
add_doc_widget("goto_tag_definition1");
737
add_doc_widget("goto_tag_declaration1");
665
738
add_doc_toolitem("Close");
666
739
add_doc_toolitem("CloseAll");
667
740
add_doc_toolitem("Search");
811
884
item = ui_lookup_widget(main_widgets.window, widget_name);
812
885
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), TRUE);
887
if (iprefs->width >= 1 && iprefs->width <= 8)
891
name = g_strdup_printf("indent_width_%d", iprefs->width);
892
item = ui_lookup_widget(main_widgets.window, name);
893
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), TRUE);
814
897
gtk_check_menu_item_set_active(
815
898
GTK_CHECK_MENU_ITEM(ui_lookup_widget(main_widgets.window, "set_file_readonly1")),
1382
/* Prepends the active text to the drop down list, unless the first element in
1383
* the list is identical, ensuring there are <= history_len elements. */
1384
void ui_combo_box_add_to_history(GtkComboBox *combo, const gchar *text)
1386
const gint history_len = 30;
1465
static gboolean tree_model_find_text(GtkTreeModel *model,
1466
GtkTreeIter *iter, gint column, const gchar *text)
1469
gboolean found = FALSE;
1471
if (gtk_tree_model_get_iter_first(model, iter))
1475
gtk_tree_model_get(model, iter, 0, &combo_text, -1);
1476
found = utils_str_equal(combo_text, text);
1482
while (gtk_tree_model_iter_next(model, iter));
1488
/** Prepends @a text to the drop down list, removing a duplicate element in
1489
* the list if found. Also ensures there are <= @a history_len elements.
1490
* @param combo_entry .
1491
* @param text Text to add, or @c NULL for current entry text.
1492
* @param history_len Max number of items, or @c 0 for default. */
1493
void ui_combo_box_add_to_history(GtkComboBoxEntry *combo_entry,
1494
const gchar *text, gint history_len)
1496
GtkComboBox *combo = GTK_COMBO_BOX(combo_entry);
1387
1497
GtkTreeModel *model;
1388
1498
GtkTreeIter iter;
1390
gboolean equal = FALSE;
1391
1499
GtkTreePath *path;
1501
if (history_len <= 0)
1504
text = gtk_entry_get_text(GTK_ENTRY(GTK_BIN(combo)->child));
1393
1506
model = gtk_combo_box_get_model(combo);
1394
if (gtk_tree_model_get_iter_first(model, &iter))
1508
if (tree_model_find_text(model, &iter, 0, text))
1396
gtk_tree_model_get(model, &iter, 0, &combo_text, -1);
1397
equal = utils_str_equal(combo_text, text);
1510
gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
1400
if (equal) return; /* don't prepend duplicate */
1402
1512
gtk_combo_box_prepend_text(combo, text);
1404
1514
/* limit history */
1418
1528
GtkTreeModel *model;
1419
1529
GtkTreeIter iter;
1421
gboolean found = FALSE;
1423
1531
model = gtk_combo_box_get_model(combo);
1424
if (gtk_tree_model_get_iter_first(model, &iter))
1428
gtk_tree_model_get(model, &iter, 0, &combo_text, -1);
1429
found = utils_str_equal(combo_text, text);
1432
while (!found && gtk_tree_model_iter_next(model, &iter));
1532
if (tree_model_find_text(model, &iter, 0, text))
1435
1533
return; /* don't prepend duplicate */
1437
1535
gtk_combo_box_prepend_text(combo, text);
1595
1693
g_object_set_data_full(G_OBJECT(open_btn), "title", g_strdup(title),
1596
1694
(GDestroyNotify) g_free);
1597
1695
g_object_set_data(G_OBJECT(open_btn), "action", (gpointer) action);
1598
g_object_set_data_full(G_OBJECT(open_btn), "entry",
1599
g_object_ref(path_entry), (GDestroyNotify) g_object_unref);
1696
ui_hookup_widget(open_btn, path_entry, "entry");
1600
1697
g_signal_connect(open_btn, "clicked", G_CALLBACK(ui_path_box_open_clicked), open_btn);
1889
static void on_editor_menu_show(GtkWidget *item)
1891
GtkWidget *popup = ui_lookup_widget(main_widgets.editor_menu, "commands1");
1892
GtkWidget *bar = ui_lookup_widget(main_widgets.window, "commands2");
1894
ui_menu_move(widgets.commands_menu, bar, popup);
1896
popup = ui_lookup_widget(main_widgets.editor_menu, "menu_format2");
1897
bar = ui_lookup_widget(main_widgets.window, "menu_format1");
1898
ui_menu_move(widgets.format_menu, bar, popup);
1902
static void on_editor_menu_hide(GtkWidget *item)
1904
GtkWidget *popup = ui_lookup_widget(main_widgets.editor_menu, "commands1");
1905
GtkWidget *bar = ui_lookup_widget(main_widgets.window, "commands2");
1907
ui_menu_move(widgets.commands_menu, popup, bar);
1909
popup = ui_lookup_widget(main_widgets.editor_menu, "menu_format2");
1910
bar = ui_lookup_widget(main_widgets.window, "menu_format1");
1911
ui_menu_move(widgets.format_menu, popup, bar);
1986
typedef struct GeanySharedMenu
1989
gchar *menubar_item;
1994
#define foreach_menu(item, array) \
1995
for (item = array; item->menu; item++)
1997
static void on_editor_menu_show(GtkWidget *widget, GeanySharedMenu *items)
1999
GeanySharedMenu *item;
2001
foreach_menu(item, items)
2003
GtkWidget *popup = ui_lookup_widget(main_widgets.editor_menu, item->popup_item);
2004
GtkWidget *bar = ui_lookup_widget(main_widgets.window, item->menubar_item);
2005
GtkWidget *menu = ui_lookup_widget(main_widgets.window, item->menu);
2007
ui_menu_move(menu, bar, popup);
2012
static void on_editor_menu_hide(GtkWidget *widget, GeanySharedMenu *items)
2014
GeanySharedMenu *item;
2016
foreach_menu(item, items)
2018
GtkWidget *popup = ui_lookup_widget(main_widgets.editor_menu, item->popup_item);
2019
GtkWidget *bar = ui_lookup_widget(main_widgets.window, item->menubar_item);
2020
GtkWidget *menu = ui_lookup_widget(main_widgets.window, item->menu);
2022
ui_menu_move(menu, popup, bar);
2027
/* Currently ui_init() is called before keyfile.c stash group code is initialized,
2028
* so this is called after that's done. */
2029
void ui_init_prefs(void)
2031
StashGroup *group = stash_group_new(PACKAGE);
2033
/* hidden prefs (don't overwrite them so users can edit them manually) */
2034
configuration_add_pref_group(group, FALSE);
2035
stash_group_set_write_once(group, TRUE);
2037
stash_group_add_boolean(group, &interface_prefs.show_symbol_list_expanders,
2038
"show_symbol_list_expanders", TRUE);
2039
stash_group_add_boolean(group, &interface_prefs.compiler_tab_autoscroll,
2040
"compiler_tab_autoscroll", TRUE);
2041
stash_group_add_boolean(group, &ui_prefs.allow_always_save,
2042
"allow_always_save", FALSE);
2043
stash_group_add_string(group, &statusbar_template,
2044
"statusbar_template", "");
2045
stash_group_add_boolean(group, &ui_prefs.new_document_after_close,
2046
"new_document_after_close", FALSE);
1915
2050
void ui_init(void)
1919
2052
init_recent_files();
1921
2054
ui_widgets.statusbar = ui_lookup_widget(main_widgets.window, "statusbar");
1924
2057
main_widgets.progressbar = progress_bar_create();
2059
/* current word sensitive items */
1926
2060
widgets.popup_goto_items[0] = ui_lookup_widget(main_widgets.editor_menu, "goto_tag_definition1");
1927
widgets.popup_goto_items[1] = ui_lookup_widget(main_widgets.editor_menu, "goto_tag_declaration1");
2061
widgets.popup_goto_items[1] = ui_lookup_widget(main_widgets.editor_menu, "context_action1");
1928
2062
widgets.popup_goto_items[2] = ui_lookup_widget(main_widgets.editor_menu, "find_usage1");
1929
2063
widgets.popup_goto_items[3] = ui_lookup_widget(main_widgets.editor_menu, "find_document_usage1");
1930
2065
widgets.popup_copy_items[0] = ui_lookup_widget(main_widgets.editor_menu, "cut1");
1931
2066
widgets.popup_copy_items[1] = ui_lookup_widget(main_widgets.editor_menu, "copy1");
1932
2067
widgets.popup_copy_items[2] = ui_lookup_widget(main_widgets.editor_menu, "delete1");
1942
2077
widgets.undo_items[0] = ui_lookup_widget(main_widgets.editor_menu, "undo1");
1943
2078
widgets.undo_items[1] = ui_lookup_widget(main_widgets.window, "menu_undo2");
1945
item = ui_lookup_widget(main_widgets.window, "menu_format1");
1946
widgets.format_menu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(item));
1947
item = ui_lookup_widget(main_widgets.window, "commands2");
1948
widgets.commands_menu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(item));
2080
/* reparent context submenus as needed */
2082
GeanySharedMenu arr[] = {
2083
{"commands2_menu", "commands2", "commands1"},
2084
{"menu_format1_menu", "menu_format1", "menu_format2"},
2085
{"more1_menu", "more1", "search2"},
2088
static GeanySharedMenu items[G_N_ELEMENTS(arr)];
1950
/* reparent edit submenus as needed */
1951
item = main_widgets.editor_menu;
1952
g_signal_connect(item, "show", G_CALLBACK(on_editor_menu_show), NULL);
1953
g_signal_connect(item, "hide", G_CALLBACK(on_editor_menu_hide), NULL);
2090
memcpy(items, arr, sizeof(arr));
2091
g_signal_connect(main_widgets.editor_menu, "show", G_CALLBACK(on_editor_menu_show), items);
2092
g_signal_connect(main_widgets.editor_menu, "hide", G_CALLBACK(on_editor_menu_hide), items);
1955
2095
ui_init_toolbar_widgets();
1956
2096
init_document_widgets();
2291
2439
void ui_editable_insert_text_callback(GtkEditable *editable, gchar *new_text,
2292
2440
gint new_text_len, gint *position, gpointer data)
2294
gboolean stop_signal = FALSE;
2295
const gchar c = *new_text;
2297
/* allow inserting '+' and '-' as the first character */
2298
if (position != NULL && *position == 0)
2300
if (c != '+' && c != '-' && ! isdigit(c))
2303
/* don't insert any text when it is not a digit */
2304
else if (! isdigit(c))
2308
g_signal_stop_emission_by_name(editable, "insert-text");
2442
gboolean first = position != NULL && *position == 0;
2445
if (new_text_len == -1)
2446
new_text_len = strlen(new_text);
2448
for (i = 0; i < new_text_len; i++, new_text++)
2450
if ((!first || !strchr("+-", *new_text)) && !isdigit(*new_text))
2452
g_signal_stop_emission_by_name(editable, "insert-text");
2460
/* gets the icon that applies to a particular MIME type */
2461
GdkPixbuf *ui_get_mime_icon(const gchar *mime_type, GtkIconSize size)
2463
GdkPixbuf *icon = NULL;
2464
#if defined(HAVE_GIO) && GLIB_CHECK_VERSION(2, 18, 0)
2468
GtkIconTheme *theme;
2471
if (!gtk_icon_size_lookup(size, &real_size, NULL))
2473
g_return_val_if_reached(NULL);
2475
ctype = g_content_type_from_mime_type(mime_type);
2478
gicon = g_content_type_get_icon(ctype);
2479
theme = gtk_icon_theme_get_default();
2480
info = gtk_icon_theme_lookup_by_gicon(theme, gicon, real_size, 0);
2481
g_object_unref(gicon);
2486
icon = gtk_icon_info_load_icon(info, NULL);
2487
gtk_icon_info_free(info);
2491
/* fallback for builds without GIO or if icon lookup failed, like it might happen on Windows */
2494
const gchar *stock_id = GTK_STOCK_FILE;
2495
GtkIconSet *icon_set;
2497
if (strstr(mime_type, "directory"))
2498
stock_id = GTK_STOCK_DIRECTORY;
2500
icon_set = gtk_icon_factory_lookup_default(stock_id);
2503
icon = gtk_icon_set_render_icon(icon_set, gtk_widget_get_default_style(),
2504
gtk_widget_get_default_direction(),
2505
GTK_STATE_NORMAL, size, NULL, NULL);