' ' A minimal source file editor built around GtkSourceView. (c) PvE - April 2010. ' ' Version 1.0: initial release ' Version 1.1: compliancy to BaCon 1.0.18 ' Version 1.2: many improvements ' Version 1.3: fix crash when syntaxfile is not available ' Version 1.4: added tabbing, FIND dialog, code improvements '------------------------------------------------------------------------------------------------------------ TRAP LOCAL ' Set socket timeout to 1 second OPTION SOCKET 1 ' We will be using memory streams OPTION MEMSTREAM TRUE ' Where to put the syntaxfile CONST Config_Path$ = "/.local/share/gtksourceview-2.0/language-specs" CONST GDK_SHIFT_MASK = 1 << 0 CONST GDK_CONTROL_MASK = 1 << 2 CONST GTK_RESPONSE_ACCEPT = -3 CONST GTK_RESPONSE_OK = -5 CONST GTK_RESPONSE_CANCEL = -6 CONST GTK_RESPONSE_YES = -8 CONST GTK_RESPONSE_APPLY = -10 CONST GTK_WIN_POS_CENTER_ON_PARENT = 4 CONST GTK_DIALOG_DESTROY_WITH_PARENT = 2 CONST GTK_MESSAGE_INFO = 0 CONST GTK_MESSAGE_WARNING = 1 CONST GTK_MESSAGE_ERROR = 3 CONST GTK_BUTTONS_CLOSE = 2 CONST GTK_BUTTONS_YES_NO = 4 CONST GTK_WRAP_NONE = 0 CONST GTK_WRAP_WORD = 2 CONST GTK_STATE_NORMAL = 0 CONST GTK_ACCEL_VISIBLE = 1 CONST GTK_WINDOW_TOPLEVEL = 0 ' Memory size for GtkIter CONST DEFAULT_WIDGET_SIZE = 96 ' The notebook can have maximum pages CONST MAXPAGES = 100 CONST DEFTITLE$ = "BaCon Source Code Editor" CONST DEFVERSION$ = "1.4" ' Global ClipBoard object DECLARE ClipBoard ' NULL pointer DECLARE NUL TYPE STRING ' Hold widgets for the notebook RECORD nbook[MAXPAGES] LOCAL view LOCAL buffer LOCAL label LOCAL title$ LOCAL iter END RECORD ' Allow icons in buttons - for now intentionally commented as some Linux distros have issues with 'gconftool-2' 'IF LEN(EXEC$(CONCAT$("which gconftool-2 2>/dev/null"))) THEN SYSTEM "gconftool-2 --type boolean --set /desktop/gnome/interface/buttons_have_icons 1" ' Check if syntax file exists IF NOT(FILEEXISTS(CONCAT$(GETENVIRON$("HOME"), Config_Path$, "/bacon.lang"))) THEN PRINT "BaCon syntaxfile not found! Fetching from BaCon website... "; CALL Update_Syntaxfile(0) PRINT "done." END IF ' Find libraries and import symbols CALL Find_Gtk_Library CALL Find_GtkSource_Library CALL Find_Gdk_Library CALL Find_Gobject_Library CALL Find_Pango_Library ' Run the GUI CALL Build_Gui '------------------------------------------------------------------------------------------------------------ ' Let's get the GTK library SUB Find_Gtk_Library LOCAL lib$ LOCAL seq, retry CATCH GOTO handle_error lib$ = "libgtk-x11-2.0.so" seq = -1 LABEL import_retry INCR seq retry = FALSE IMPORT "gtk_init(int*,void*)" FROM lib$ TYPE void IF retry THEN GOTO import_retry GOTO contin LABEL handle_error ERROR = 0 IF seq IS 0 THEN lib$ = "libgtk-x11-2.0.so.0" ELSE lib$ = CONCAT$(LEFT$(lib$, INSTRREV(lib$, ".")), STR$(seq)) IF seq < 50 THEN retry = TRUE ELSE PRINT "Gtk library not found!" END END IF RESUME LABEL contin CATCH GOTO lookup_error IMPORT "gtk_accel_group_new" FROM lib$ TYPE long IMPORT "gtk_box_pack_end(long,long,int,int,int)" FROM lib$ TYPE void IMPORT "gtk_box_pack_start(long,long,int,int,int)" FROM lib$ TYPE void IMPORT "gtk_button_new_from_stock(char*)" FROM lib$ TYPE long IMPORT "gtk_check_menu_item_get_active(long)" FROM lib$ TYPE int IMPORT "gtk_check_menu_item_set_active(long,int)" FROM lib$ TYPE void IMPORT "gtk_check_menu_item_new_with_mnemonic(char*)" FROM lib$ TYPE long IMPORT "gtk_clipboard_get(long)" FROM lib$ TYPE long IMPORT "gtk_color_selection_dialog_new(char*)" FROM lib$ TYPE long IMPORT "gtk_color_selection_get_current_color(long,long)" FROM lib$ TYPE void IMPORT "gtk_color_selection_palette_from_string(char*,long,long)" FROM lib$ TYPE int IMPORT "gtk_color_selection_palette_to_string(long,int)" FROM lib$ TYPE char* IMPORT "gtk_color_selection_set_current_color(long,long)" FROM lib$ TYPE void IMPORT "gtk_container_add(long,long)" FROM lib$ TYPE void IMPORT "gtk_dialog_run(long)" FROM lib$ TYPE int IMPORT "gtk_entry_get_text(long)" FROM lib$ TYPE char* IMPORT "gtk_entry_new" FROM lib$ TYPE long IMPORT "gtk_events_pending" FROM lib$ TYPE int IMPORT "gtk_exit(int)" FROM lib$ TYPE void IMPORT "gtk_file_chooser_dialog_new(char*,long,int,char*,...)" FROM lib$ TYPE long IMPORT "gtk_file_chooser_get_filename(long)" FROM lib$ TYPE char* IMPORT "gtk_font_selection_dialog_get_font_name(long)" FROM lib$ TYPE char* IMPORT "gtk_font_selection_dialog_new(char*)" FROM lib$ TYPE long IMPORT "gtk_font_selection_dialog_set_font_name(long,char*)" FROM lib$ TYPE int IMPORT "gtk_hbox_new(int,int)" FROM lib$ TYPE long IMPORT "gtk_label_new(char*)" FROM lib$ TYPE long IMPORT "gtk_label_get_text(long)" FROM lib$ TYPE char* IMPORT "gtk_label_set_text(long,char*)" FROM lib$ TYPE void IMPORT "gtk_main" FROM lib$ TYPE void IMPORT "gtk_main_iteration_do(int)" FROM lib$ TYPE int IMPORT "gtk_menu_bar_new" FROM lib$ TYPE long IMPORT "gtk_menu_item_new" FROM lib$ TYPE long IMPORT "gtk_menu_item_new_with_mnemonic(char*)" FROM lib$ TYPE long IMPORT "gtk_menu_item_set_submenu(long,long)" FROM lib$ TYPE void IMPORT "gtk_menu_new" FROM lib$ TYPE long IMPORT "gtk_menu_popup(long,long,long,void*,void*,int,int)" FROM lib$ TYPE void IMPORT "gtk_menu_set_title(long,char*)" FROM lib$ TYPE void IMPORT "gtk_menu_shell_append(long,long)" FROM lib$ TYPE void IMPORT "gtk_message_dialog_new(long,int,int,int,char*,...)" FROM lib$ TYPE long IMPORT "gtk_notebook_append_page(long,long,long)" FROM lib$ TYPE int IMPORT "gtk_notebook_get_tab_label_text(long,long)" FROM lib$ TYPE char* IMPORT "gtk_notebook_get_current_page(long)" FROM lib$ TYPE int IMPORT "gtk_notebook_get_n_pages(long)" FROM lib$ TYPE int IMPORT "gtk_notebook_new" FROM lib$ TYPE long IMPORT "gtk_notebook_remove_page(long,int)" FROM lib$ TYPE void IMPORT "gtk_notebook_set_current_page(long,int)" FROM lib$ TYPE void IMPORT "gtk_scrolled_window_new(long,long)" FROM lib$ TYPE long IMPORT "gtk_scrolled_window_set_policy(long,int,int)" FROM lib$ TYPE void IMPORT "gtk_scrolled_window_set_shadow_type(long,int)" FROM lib$ TYPE void IMPORT "gtk_show_about_dialog(long,char*,...)" FROM lib$ TYPE void IMPORT "gtk_statusbar_get_context_id(long,char*)" FROM lib$ TYPE int IMPORT "gtk_statusbar_new" FROM lib$ TYPE long IMPORT "gtk_statusbar_pop(long,int)" FROM lib$ TYPE void IMPORT "gtk_statusbar_push(long,int,char*)" FROM lib$ TYPE int IMPORT "gtk_text_buffer_backspace(long,long,int,int)" FROM lib$ TYPE int IMPORT "gtk_text_buffer_copy_clipboard(long,long)" FROM lib$ TYPE void IMPORT "gtk_text_buffer_cut_clipboard(long,long,int)" FROM lib$ TYPE void IMPORT "gtk_text_buffer_get_bounds(long,long,long)" FROM lib$ TYPE void IMPORT "gtk_text_buffer_get_end_iter(long,long)" FROM lib$ TYPE void IMPORT "gtk_text_buffer_get_selection_bound(long)" FROM lib$ TYPE long IMPORT "gtk_text_buffer_get_start_iter(long,long)" FROM lib$ TYPE void IMPORT "gtk_text_buffer_get_text(long,long,long,int)" FROM lib$ TYPE char* IMPORT "gtk_text_buffer_paste_clipboard(long,long,void*,int)" FROM lib$ TYPE void IMPORT "gtk_text_buffer_select_range(long,long,long)" FROM lib$ TYPE void IMPORT "gtk_text_buffer_set_text(long,char*,int)" FROM lib$ TYPE void IMPORT "gtk_text_iter_forward_search(long,char*,int,long,long,void*)" FROM lib$ TYPE int IMPORT "gtk_text_view_scroll_to_mark(long,long,double,int,double,double)" FROM lib$ TYPE void IMPORT "gtk_text_view_set_wrap_mode(long,int)" FROM lib$ TYPE void IMPORT "gtk_vbox_new(int,int)" FROM lib$ TYPE long IMPORT "gtk_widget_add_accelerator(long,char*,long,int,int,int)" FROM lib$ TYPE void IMPORT "gtk_widget_destroy(long)" FROM lib$ TYPE void IMPORT "gtk_widget_grab_focus(long)" FROM lib$ TYPE void IMPORT "gtk_widget_hide(long)" FROM lib$ TYPE void IMPORT "gtk_widget_modify_base(long,int,long)" FROM lib$ TYPE void IMPORT "gtk_widget_modify_font(long,long)" FROM lib$ TYPE void IMPORT "gtk_widget_set_sensitive(long,int)" FROM lib$ TYPE void IMPORT "gtk_widget_set_size_request(long,int,int)" FROM lib$ TYPE void IMPORT "gtk_widget_show_all(long)" FROM lib$ TYPE void IMPORT "gtk_window_add_accel_group(long,long)" FROM lib$ TYPE void IMPORT "gtk_window_get_title(long)" FROM lib$ TYPE char* IMPORT "gtk_window_new(int)" FROM lib$ TYPE long IMPORT "gtk_window_set_default_size(long,int,int)" FROM lib$ TYPE void IMPORT "gtk_window_set_icon_name(long,char*)" FROM lib$ TYPE void IMPORT "gtk_window_set_position(long,int)" FROM lib$ TYPE void IMPORT "gtk_window_set_title(long,char*)" FROM lib$ TYPE void IMPORT "gtk_window_set_transient_for(long,long)" FROM lib$ TYPE void GOTO Exit_Sub LABEL lookup_error PRINT ERR$(ERROR) END LABEL Exit_Sub CATCH RESET END SUB '------------------------------------------------------------------------------------------------------------ ' Let's get the GtkSource library SUB Find_GtkSource_Library LOCAL lib$ LOCAL seq, retry CATCH GOTO handle_error lib$ = "libgtksourceview-2.0.so" seq = -1 LABEL import_retry INCR seq retry = FALSE IMPORT "gtk_source_buffer_new_with_language(long)" FROM lib$ TYPE long IF retry THEN GOTO import_retry GOTO contin LABEL handle_error ERROR = 0 IF seq IS 0 THEN lib$ = "libgtksourceview-2.0.so.0" ELSE lib$ = CONCAT$(LEFT$(lib$, INSTRREV(lib$, ".")), STR$(seq)) IF seq < 50 THEN retry = TRUE ELSE PRINT "GtkSourceView library not found!" END END IF RESUME LABEL contin CATCH GOTO lookup_error IMPORT "gtk_source_buffer_can_undo(long)" FROM lib$ TYPE int IMPORT "gtk_source_buffer_set_highlight_matching_brackets(long,int)" FROM lib$ TYPE void IMPORT "gtk_source_buffer_undo(long)" FROM lib$ TYPE void IMPORT "gtk_source_language_manager_get_default" FROM lib$ TYPE long IMPORT "gtk_source_language_manager_get_language(long,char*)" FROM lib$ TYPE long IMPORT "gtk_source_view_new_with_buffer(long)" FROM lib$ TYPE long IMPORT "gtk_source_view_set_auto_indent(long,int)" FROM lib$ TYPE void IMPORT "gtk_source_view_set_show_line_numbers(long,int)" FROM lib$ TYPE void IMPORT "gtk_source_view_set_tab_width(long,int)" FROM lib$ TYPE void GOTO Exit_Sub LABEL lookup_error PRINT ERR$(ERROR) END LABEL Exit_Sub CATCH RESET END SUB '------------------------------------------------------------------------------------------------------------ ' Let's get the Gdk library SUB Find_Gdk_Library LOCAL lib$ LOCAL seq, retry CATCH GOTO handle_error lib$ = "libgdk-x11-2.0.so" seq = -1 LABEL import_retry INCR seq retry = FALSE IMPORT "gdk_atom_intern(char*,int)" FROM lib$ TYPE long IF retry THEN GOTO import_retry GOTO contin LABEL handle_error ERROR = 0 IF seq IS 0 THEN lib$ = "libgdk-x11-2.0.so.0" ELSE lib$ = CONCAT$(LEFT$(lib$, INSTRREV(lib$, ".")), STR$(seq)) IF seq < 50 THEN retry = TRUE ELSE PRINT "Gdk library not found!" END END IF RESUME LABEL contin CATCH GOTO lookup_error IMPORT "gdk_keyval_from_name(char*)" FROM lib$ TYPE int IMPORT "gdk_window_at_pointer(long,long)" FROM lib$ TYPE long IMPORT "gdk_window_get_pointer(long,long,long,long)" FROM lib$ TYPE long GOTO Exit_Sub LABEL lookup_error PRINT ERR$(ERROR) END LABEL Exit_Sub CATCH RESET END SUB '------------------------------------------------------------------------------------------------------------ ' Let's get the GtkObject library SUB Find_Gobject_Library LOCAL lib$ LOCAL seq, retry CATCH GOTO handle_error lib$ = "libgobject-2.0.so" seq = -1 LABEL import_retry INCR seq retry = FALSE IMPORT "g_signal_connect_data(long,char*,void*,long,long,int)" FROM lib$ TYPE void IF retry THEN GOTO import_retry GOTO contin LABEL handle_error ERROR = 0 IF seq IS 0 THEN lib$ = "libgobject-2.0.so.0" ELSE lib$ = CONCAT$(LEFT$(lib$, INSTRREV(lib$, ".")), STR$(seq)) IF seq < 50 THEN retry = TRUE ELSE PRINT "GtkObject library not found!" END END IF RESUME LABEL contin CATCH GOTO lookup_error IMPORT "g_object_get(long,char*,...)" FROM lib$ TYPE void GOTO Exit_Sub LABEL lookup_error PRINT ERR$(ERROR) END LABEL Exit_Sub CATCH RESET END SUB '------------------------------------------------------------------------------------------------------------ ' Let's get the Pango library SUB Find_Pango_Library LOCAL lib$ LOCAL seq, retry CATCH GOTO handle_error lib$ = "libpango-1.0.so" seq = -1 LABEL import_retry INCR seq retry = FALSE IMPORT "pango_font_description_from_string(char*)" FROM lib$ TYPE long IF retry THEN GOTO import_retry GOTO contin LABEL handle_error ERROR = 0 IF seq IS 0 THEN lib$ = "libpango-1.0.so.0" ELSE lib$ = CONCAT$(LEFT$(lib$, INSTRREV(lib$, ".")), STR$(seq)) IF seq < 50 THEN retry = TRUE ELSE PRINT "Pango library not found!" END END IF RESUME LABEL contin CATCH GOTO lookup_error IMPORT "pango_font_description_free(long)" FROM lib$ TYPE void GOTO Exit_Sub LABEL lookup_error PRINT ERR$(ERROR) END LABEL Exit_Sub CATCH RESET END SUB '------------------------------------------------------------------------------------------------------------ SUB Update_Syntaxfile(NUMBER use_gui) LOCAL dat$, total$, home$ LOCAL bacon, dialog LOCAL syntaxfile TYPE FILE* ' Update GUI IF use_gui THEN WHILE gtk_events_pending() gtk_main_iteration_do(FALSE) WEND END IF home$ = GETENVIRON$("HOME") ' Enable check on internet address CATCH GOTO error ' Fetch the latest syntaxfile OPEN "www.basic-converter.org:80" FOR NETWORK AS bacon SEND "GET /bacon.lang HTTP/1.1\r\nHost: www.basic-converter.org\r\n\r\n" TO bacon REPEAT RECEIVE dat$ FROM bacon total$ = CONCAT$(total$, dat$) UNTIL ISFALSE(WAIT(bacon, 500)) CLOSE NETWORK bacon ' Create directories MAKEDIR CONCAT$(home$, "/.local/share/gtksourceview-2.0/language-specs") ' Save syntax file from BaCon website to correct location OPEN CONCAT$(home$, Config_Path$, "/bacon.lang") FOR WRITING AS syntaxfile WRITELN MID$(total$, INSTR(total$, " 0 THEN OPEN nbook[page].title$ FOR WRITING AS sourcefile WRITELN Get_Contents$() TO sourcefile CLOSE FILE sourcefile gtk_label_set_text(nbook[page].label, MID$(nbook[page].title$, INSTRREV(nbook[page].title$, "/")+1) ) Statusbar_Msg(CONCAT$("Current code saved to '", nbook[page].title$, "'.")) ELSE response = gtk_dialog_run(save_dialog) END IF END SUB '------------------------------------------------------------------------------------------------------------ ' Callback for SAVE AS SUB Save_Fileas gtk_widget_show_all(save_dialog) END SUB '------------------------------------------------------------------------------------------------------------ ' Handle SAVE AS dialog actions SUB Handle_Save_Dialog(NUMBER widget, int action) LOCAL file_overwrite, page LOCAL response TYPE int ' Define by reference LOCAL name TYPE STRING gtk_widget_hide(save_dialog) IF action IS GTK_RESPONSE_ACCEPT THEN name = gtk_file_chooser_get_filename(widget) IF FILEEXISTS(name) THEN file_overwrite = gtk_message_dialog_new(win, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, \ GTK_BUTTONS_YES_NO, CONCAT$("Overwrite existing '", MID$(name, INSTRREV(name, "/")+1), "'?"), NUL) gtk_window_set_title(file_overwrite, "Warning!") response = gtk_dialog_run(file_overwrite) gtk_widget_destroy(file_overwrite) ELSE response = GTK_RESPONSE_YES END IF IF response IS GTK_RESPONSE_YES THEN OPEN name FOR WRITING AS sourcefile WRITELN Get_Contents$() TO sourcefile CLOSE FILE sourcefile page = gtk_notebook_get_current_page(notebook) gtk_label_set_text(nbook[page].label, MID$(name, INSTRREV(name, "/")+1) ) Statusbar_Msg(CONCAT$("Current code saved to '", name, "'.")) nbook[page].title$ = name ELSE Statusbar_Msg(CONCAT$("Save cancelled.")) END IF END IF END SUB '------------------------------------------------------------------------------------------------------------ SUB Set_Indent LOCAL x FOR x = 0 TO gtk_notebook_get_n_pages(notebook)-1 gtk_source_view_set_auto_indent(nbook[x].view, gtk_check_menu_item_get_active(indent_menu)) NEXT Save_Defaults END SUB '------------------------------------------------------------------------------------------------------------ SUB Set_Linenr LOCAL x FOR x = 0 TO gtk_notebook_get_n_pages(notebook)-1 gtk_source_view_set_show_line_numbers(nbook[x].view, gtk_check_menu_item_get_active(linenr_menu)) NEXT Save_Defaults END SUB '------------------------------------------------------------------------------------------------------------ ' At each keystroke set title to 'changed' SUB Set_Changed LOCAL title$ LOCAL page page = gtk_notebook_get_current_page(notebook) title$ = gtk_label_get_text(nbook[page].label) IF NOT(EQUAL(LEFT$(title$, 1), "*")) THEN gtk_label_set_text(nbook[page].label, CONCAT$("* ", title$) ) END IF END SUB '------------------------------------------------------------------------------------------------------------ SUB Set_Wrapmode LOCAL x IF gtk_check_menu_item_get_active(wrap_menu) THEN FOR x = 0 TO gtk_notebook_get_n_pages(notebook)-1 gtk_text_view_set_wrap_mode(nbook[x].view, GTK_WRAP_WORD) NEXT ELSE FOR x = 0 TO gtk_notebook_get_n_pages(notebook)-1 gtk_text_view_set_wrap_mode(nbook[x].view, GTK_WRAP_NONE) NEXT ENDIF Save_Defaults END SUB '------------------------------------------------------------------------------------------------------------ ' Callback for SELECT FONT SUB Select_Font gtk_widget_show_all(font_dialog) END SUB '------------------------------------------------------------------------------------------------------------ ' Handle FONT selection SUB Handle_Font_Dialog(NUMBER widget, int action) LOCAL name TYPE STRING LOCAL desc, x IF action IS GTK_RESPONSE_CANCEL OR action IS GTK_RESPONSE_OK THEN gtk_widget_hide(font_dialog) IF action IS GTK_RESPONSE_OK OR action IS GTK_RESPONSE_APPLY THEN name = gtk_font_selection_dialog_get_font_name(font_dialog) desc = pango_font_description_from_string(name) FOR x = 0 TO gtk_notebook_get_n_pages(notebook)-1 gtk_widget_modify_font(nbook[x].view, desc) NEXT pango_font_description_free(desc) Statusbar_Msg(CONCAT$("Font has been changed to '", name, "'.")) Save_Defaults END IF END SUB '------------------------------------------------------------------------------------------------------------ ' Callback for SELECT COLOR SUB Select_Color gtk_widget_show_all(color_dialog) END SUB '------------------------------------------------------------------------------------------------------------ ' Handle COLOR selection SUB Handle_Color_Dialog(NUMBER widget, int action) LOCAL colselect, gdkcol, x gtk_widget_hide(color_dialog) IF action IS GTK_RESPONSE_OK THEN g_object_get(color_dialog, "color-selection", ADDRESS(colselect), NUL) gdkcol = MEMORY(DEFAULT_WIDGET_SIZE) gtk_color_selection_get_current_color(colselect, gdkcol) FOR x = 0 TO gtk_notebook_get_n_pages(notebook)-1 gtk_widget_modify_base(nbook[x].view, GTK_STATE_NORMAL, gdkcol) NEXT Statusbar_Msg(CONCAT$("Color was successfully changed.")) FREE gdkcol Save_Defaults END IF END SUB '------------------------------------------------------------------------------------------------------------ ' Update syntax file SUB Get_Syntax Update_Syntaxfile(1) Statusbar_Msg(CONCAT$("Updated BaCon language file!")) END SUB '------------------------------------------------------------------------------------------------------------ ' Info dialog SUB Show_Info gtk_show_about_dialog(win, "program-name", DEFTITLE$, "version", DEFVERSION$, "copyright", "(c) Peter van Eerten", \ "comments", "An editor built around GtkSourceView.", "website", "http://www.basic-converter.org/", NUL) END SUB '------------------------------------------------------------------------------------------------------------ SUB Cut_Text LOCAL page page = gtk_notebook_get_current_page(notebook) gtk_text_buffer_cut_clipboard(nbook[page].buffer, ClipBoard, 1) END SUB '------------------------------------------------------------------------------------------------------------ SUB Copy_Text LOCAL page page = gtk_notebook_get_current_page(notebook) gtk_text_buffer_copy_clipboard(nbook[page].buffer, ClipBoard) END SUB '------------------------------------------------------------------------------------------------------------ SUB Paste_Text LOCAL page page = gtk_notebook_get_current_page(notebook) gtk_text_buffer_paste_clipboard(nbook[page].buffer, ClipBoard, NUL, 1) END SUB '------------------------------------------------------------------------------------------------------------ SUB Undo_Action LOCAL page page = gtk_notebook_get_current_page(notebook) IF gtk_source_buffer_can_undo(nbook[page].buffer) THEN gtk_source_buffer_undo(nbook[page].buffer) END SUB '------------------------------------------------------------------------------------------------------------ SUB Select_All LOCAL page, start_iter, end_iter start_iter = MEMORY(DEFAULT_WIDGET_SIZE) end_iter = MEMORY(DEFAULT_WIDGET_SIZE) page = gtk_notebook_get_current_page(notebook) gtk_text_buffer_get_bounds(nbook[page].buffer, start_iter, end_iter) gtk_text_buffer_select_range(nbook[page].buffer, start_iter, end_iter) FREE start_iter FREE end_iter END SUB '------------------------------------------------------------------------------------------------------------ SUB Close_Tab LOCAL title$ LOCAL dialog, page, x LOCAL response TYPE int page = gtk_notebook_get_current_page(notebook) IF page >= 0 THEN title$ = gtk_label_get_text(nbook[page].label) IF EQUAL(LEFT$(title$, 1), "*") THEN dialog = gtk_message_dialog_new(win, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, GTK_BUTTONS_YES_NO, CONCAT$("Save program '", MID$(title$, 2), "' ?"), NUL) gtk_window_set_title(dialog, "Warning!") response = gtk_dialog_run(dialog) gtk_widget_destroy(dialog) IF response IS GTK_RESPONSE_YES THEN Save_File END IF gtk_notebook_remove_page(notebook, page) ' Scroll record array FOR x = page TO gtk_notebook_get_n_pages(notebook)-1 nbook[x].view = nbook[x+1].view nbook[x].buffer = nbook[x+1].buffer nbook[x].label = nbook[x+1].label nbook[x].title$ = nbook[x+1].title$ NEXT END IF ' If there are no tabs, disable some of the menus IF gtk_notebook_get_n_pages(notebook) IS 0 THEN gtk_widget_set_sensitive(file_menu, FALSE) gtk_widget_set_sensitive(save_menu, FALSE) gtk_widget_set_sensitive(saveas_menu, FALSE) gtk_widget_set_sensitive(closetab_menu, FALSE) gtk_widget_set_sensitive(cut_menu, FALSE) gtk_widget_set_sensitive(copy_menu, FALSE) gtk_widget_set_sensitive(paste_menu, FALSE) gtk_widget_set_sensitive(select_menu, FALSE) gtk_widget_set_sensitive(undo_menu, FALSE) gtk_widget_set_sensitive(find_menu, FALSE) gtk_widget_set_sensitive(indent_menu, FALSE) gtk_widget_set_sensitive(linenr_menu, FALSE) gtk_widget_set_sensitive(wrap_menu, FALSE) gtk_widget_set_sensitive(font_menu, FALSE) gtk_widget_set_sensitive(color_menu, FALSE) END IF END SUB '------------------------------------------------------------------------------------------------------------ ' Callback for exit SUB Exit_Prog REPEAT Close_Tab UNTIL gtk_notebook_get_n_pages(notebook) IS 0 Save_Defaults ' Use normal 'exit' as gtk_exit is deprecated END ENDSUB '------------------------------------------------------------------------------------------------------------ SUB Create_Page LOCAL lm, lang, buffer, view, scrolled, label, page ' Create language manager lm = gtk_source_language_manager_get_default() ' Define language lang = gtk_source_language_manager_get_language(lm, "bacon") ' Setup buffer and viewer using BaCon as language buffer = gtk_source_buffer_new_with_language(lang) g_signal_connect_data(buffer, "changed", Set_Changed, 0, 0, 0) gtk_source_buffer_set_highlight_matching_brackets(buffer, 1) view = gtk_source_view_new_with_buffer(buffer) ' Tab space to 4 characters gtk_source_view_set_tab_width(view, 4) ' Create scrolled window scrolled = gtk_scrolled_window_new(0, 0) gtk_scrolled_window_set_policy(scrolled, 1, 1) gtk_scrolled_window_set_shadow_type(scrolled, 3) gtk_container_add(scrolled, view) ' Create the tab label = gtk_label_new("New") page = gtk_notebook_append_page(notebook, scrolled, label) ' Set new tab as active gtk_widget_show_all(notebook) gtk_notebook_set_current_page(notebook, page) ' Store new widgets nbook[page].view = view nbook[page].buffer = buffer nbook[page].label = label nbook[page].title$ = "" IF gtk_notebook_get_n_pages(notebook) IS 1 THEN gtk_widget_set_sensitive(file_menu, TRUE) gtk_widget_set_sensitive(save_menu, TRUE) gtk_widget_set_sensitive(saveas_menu, TRUE) gtk_widget_set_sensitive(closetab_menu, TRUE) gtk_widget_set_sensitive(cut_menu, TRUE) gtk_widget_set_sensitive(copy_menu, TRUE) gtk_widget_set_sensitive(paste_menu, TRUE) gtk_widget_set_sensitive(select_menu, TRUE) gtk_widget_set_sensitive(undo_menu, TRUE) gtk_widget_set_sensitive(find_menu, TRUE) gtk_widget_set_sensitive(indent_menu, TRUE) gtk_widget_set_sensitive(linenr_menu, TRUE) gtk_widget_set_sensitive(wrap_menu, TRUE) gtk_widget_set_sensitive(font_menu, TRUE) gtk_widget_set_sensitive(color_menu, TRUE) END IF gtk_widget_grab_focus(view) ' Get the default settings for the new page IF FILEEXISTS(CONCAT$(GETENVIRON$("HOME"), "/.bacon.txt")) THEN Load_Defaults END SUB '------------------------------------------------------------------------------------------------------------ SUB Open_Page Create_Page Open_File END SUB '------------------------------------------------------------------------------------------------------------ SUB Start_Find gtk_widget_show_all(find) gtk_widget_grab_focus(find_entry) END SUB '------------------------------------------------------------------------------------------------------------ SUB Hide_Find LOCAL page gtk_widget_hide(find) page = gtk_notebook_get_current_page(notebook) IF nbook[page].iter ISNOT 0 THEN FREE nbook[page].iter nbook[page].iter = 0 END SUB '------------------------------------------------------------------------------------------------------------ ' Action to find term and scroll text_view to that place SUB Find_Term LOCAL iter, start_iter, end_iter, page, result, find_warning, response, mark LOCAL text$ text$ = gtk_entry_get_text(find_entry) page = gtk_notebook_get_current_page(notebook) IF nbook[page].iter IS 0 THEN nbook[page].iter = MEMORY(DEFAULT_WIDGET_SIZE) gtk_text_buffer_get_start_iter(nbook[page].buffer, nbook[page].iter) END IF start_iter = MEMORY(DEFAULT_WIDGET_SIZE) end_iter = MEMORY(DEFAULT_WIDGET_SIZE) result = gtk_text_iter_forward_search(nbook[page].iter, text$, 0, start_iter, end_iter, NUL) IF NOT(result) THEN find_warning = gtk_message_dialog_new(win, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, \ GTK_BUTTONS_CLOSE, CONCAT$(NL$, "Term '", text$, "' not found!"), NUL) gtk_window_set_title(find_warning, "For your information") response = gtk_dialog_run(find_warning) gtk_widget_destroy(find_warning) FREE end_iter FREE nbook[page].iter nbook[page].iter = 0 ELSE gtk_text_buffer_select_range(nbook[page].buffer, start_iter, end_iter) mark = gtk_text_buffer_get_selection_bound(nbook[page].buffer) gtk_text_view_scroll_to_mark(nbook[page].view, mark, 0, 0, 0, 0) FREE nbook[page].iter nbook[page].iter = end_iter END IF FREE start_iter END SUB '------------------------------------------------------------------------------------------------------------ FUNCTION Show_Popup LOCAL gdkwin, mask LOCAL x, y TYPE int gdkwin = gdk_window_at_pointer(ADDRESS(x), ADDRESS(y)) gdk_window_get_pointer(gdkwin, ADDRESS(x), ADDRESS(y), ADDRESS(mask)) ' Only right mouse button should activate popup IF (mask & (1 << 10)) THEN gtk_menu_popup(cmenu, 0, 0, NUL, NUL, 3, 0) RETURN TRUE END IF ' If other button is pressed, resume default event handling RETURN FALSE END FUNCTION '------------------------------------------------------------------------------------------------------------ SUB Build_Gui LOCAL menubar, fmenu, sep1, sep5, fmenu_item1 LOCAL emenu, sep4, sep6, sep7, emenu_item1 LOCAL omenu, sep2, sep3, fmenu_item2 LOCAL hmenu, fmenu_item3 LOCAL cnewtab_menu, copentab_menu, cclosetab_menu LOCAL vbox, accel_group, find_ok, find_get, find_vbox, find_hbox ' Initialize GTK gtk_init(0, 0) ' Define main window win = gtk_window_new(GTK_WINDOW_TOPLEVEL) gtk_window_set_title(win, DEFTITLE$) gtk_window_set_position(win, 1) gtk_window_set_default_size(win, 700, 600) gtk_window_set_icon_name(win, "gtk-edit") ' Define callback when deleting window g_signal_connect_data(win, "delete-event", Exit_Prog, 0, 0, 0) ' Create FILE OPEN file_dialog = gtk_file_chooser_dialog_new("Open file...", win, 0, "gtk-cancel", GTK_RESPONSE_CANCEL, "gtk-open", GTK_RESPONSE_ACCEPT, NUL) gtk_window_set_transient_for(file_dialog, win) gtk_window_set_position(file_dialog, GTK_WIN_POS_CENTER_ON_PARENT) gtk_window_set_default_size(file_dialog, 300, 300) g_signal_connect_data(file_dialog, "delete-event", Hide_Dialog, 0, 0, 0) g_signal_connect_data(file_dialog, "response", Handle_Open_Dialog, 0, 0, 0) ' Create SAVE AS save_dialog = gtk_file_chooser_dialog_new("Save file as...", win, 1, "gtk-cancel", GTK_RESPONSE_CANCEL, "gtk-save", GTK_RESPONSE_ACCEPT, NUL) gtk_window_set_transient_for(save_dialog, win) gtk_window_set_position(save_dialog, GTK_WIN_POS_CENTER_ON_PARENT) gtk_window_set_default_size(save_dialog, 300, 300) g_signal_connect_data(save_dialog, "delete-event", Hide_Dialog, 0, 0, 0) g_signal_connect_data(save_dialog, "response", Handle_Save_Dialog, 0, 0, 0) ' Create FONT SELECTION font_dialog = gtk_font_selection_dialog_new("Select font...") gtk_window_set_transient_for(font_dialog, win) gtk_window_set_position(font_dialog, GTK_WIN_POS_CENTER_ON_PARENT) gtk_window_set_default_size(font_dialog, 300, 300) g_signal_connect_data(font_dialog, "delete-event", Hide_Dialog, 0, 0, 0) g_signal_connect_data(font_dialog, "response", Handle_Font_Dialog, 0, 0, 0) ' Create COLOR SELECTION color_dialog = gtk_color_selection_dialog_new("Select color...") gtk_window_set_transient_for(color_dialog, win) gtk_window_set_position(color_dialog, GTK_WIN_POS_CENTER_ON_PARENT) gtk_window_set_default_size(color_dialog, 300, 300) g_signal_connect_data(color_dialog, "delete-event", Hide_Dialog, 0, 0, 0) g_signal_connect_data(color_dialog, "response", Handle_Color_Dialog, 0, 0, 0) ' Define the global clipboard ClipBoard = gtk_clipboard_get(gdk_atom_intern("CLIPBOARD", 0)) ' Create menubar menubar = gtk_menu_bar_new() ' Create FILE submenu fmenu = gtk_menu_new() file_menu = gtk_menu_item_new_with_mnemonic("_Open...") save_menu = gtk_menu_item_new_with_mnemonic("_Save") saveas_menu = gtk_menu_item_new_with_mnemonic("S_ave as...") sep1 = gtk_menu_item_new() newtab_menu = gtk_menu_item_new_with_mnemonic("_New tab") opentab_menu = gtk_menu_item_new_with_mnemonic("O_pen tab...") closetab_menu = gtk_menu_item_new_with_mnemonic("_Close tab") sep5 = gtk_menu_item_new() exit_menu = gtk_menu_item_new_with_mnemonic("_Exit") gtk_menu_shell_append(fmenu, file_menu) gtk_menu_shell_append(fmenu, save_menu) gtk_menu_shell_append(fmenu, saveas_menu) gtk_menu_shell_append(fmenu, sep1) gtk_menu_shell_append(fmenu, newtab_menu) gtk_menu_shell_append(fmenu, opentab_menu) gtk_menu_shell_append(fmenu, closetab_menu) gtk_menu_shell_append(fmenu, sep5) gtk_menu_shell_append(fmenu, exit_menu) fmenu_item1 = gtk_menu_item_new_with_mnemonic("_File") gtk_menu_item_set_submenu(fmenu_item1, fmenu) gtk_menu_shell_append(menubar, fmenu_item1) ' Create EDIT submenu emenu = gtk_menu_new() cut_menu = gtk_menu_item_new_with_mnemonic("_Cut") copy_menu = gtk_menu_item_new_with_mnemonic("C_opy") paste_menu = gtk_menu_item_new_with_mnemonic("_Paste") sep4 = gtk_menu_item_new() undo_menu = gtk_menu_item_new_with_mnemonic("_Undo") sep6 = gtk_menu_item_new() select_menu = gtk_menu_item_new_with_mnemonic("_Select all") sep7 = gtk_menu_item_new() find_menu = gtk_menu_item_new_with_mnemonic("_Find...") gtk_menu_shell_append(emenu, cut_menu) gtk_menu_shell_append(emenu, copy_menu) gtk_menu_shell_append(emenu, paste_menu) gtk_menu_shell_append(emenu, sep4) gtk_menu_shell_append(emenu, undo_menu) gtk_menu_shell_append(emenu, sep6) gtk_menu_shell_append(emenu, select_menu) gtk_menu_shell_append(emenu, sep7) gtk_menu_shell_append(emenu, find_menu) emenu_item1 = gtk_menu_item_new_with_mnemonic("_Edit") gtk_menu_item_set_submenu(emenu_item1, emenu) gtk_menu_shell_append(menubar, emenu_item1) ' Create OPTIONS submenu omenu = gtk_menu_new() indent_menu = gtk_check_menu_item_new_with_mnemonic("_Auto indent") linenr_menu = gtk_check_menu_item_new_with_mnemonic("_Line numbers") wrap_menu = gtk_check_menu_item_new_with_mnemonic("_Wrap lines") sep2 = gtk_menu_item_new() font_menu = gtk_menu_item_new_with_mnemonic("_Select font...") color_menu = gtk_menu_item_new_with_mnemonic("_Background color...") sep3 = gtk_menu_item_new() syntax_menu = gtk_menu_item_new_with_mnemonic("_Update syntaxfile...") gtk_menu_shell_append(omenu, indent_menu) gtk_menu_shell_append(omenu, linenr_menu) gtk_menu_shell_append(omenu, wrap_menu) gtk_menu_shell_append(omenu, sep2) gtk_menu_shell_append(omenu, font_menu) gtk_menu_shell_append(omenu, color_menu) gtk_menu_shell_append(omenu, sep3) gtk_menu_shell_append(omenu, syntax_menu) fmenu_item2 = gtk_menu_item_new_with_mnemonic("_Options") gtk_menu_item_set_submenu(fmenu_item2, omenu) gtk_menu_shell_append(menubar, fmenu_item2) ' Create HELP submenu hmenu = gtk_menu_new() about_menu = gtk_menu_item_new_with_mnemonic("_About...") gtk_menu_shell_append(hmenu, about_menu) fmenu_item3 = gtk_menu_item_new_with_mnemonic("_Info") gtk_menu_item_set_submenu(fmenu_item3, hmenu) gtk_menu_shell_append(menubar, fmenu_item3) ' Create contextmenu cmenu = gtk_menu_new() cnewtab_menu = gtk_menu_item_new_with_mnemonic("New tab") copentab_menu = gtk_menu_item_new_with_mnemonic("Open tab...") cclosetab_menu = gtk_menu_item_new_with_mnemonic("Close tab") gtk_menu_shell_append(cmenu, cnewtab_menu) gtk_menu_shell_append(cmenu, copentab_menu) gtk_menu_shell_append(cmenu, cclosetab_menu) g_signal_connect_data(cnewtab_menu, "activate", Create_Page, 0, 0, 0) g_signal_connect_data(copentab_menu, "activate", Open_Page, 0, 0, 0) g_signal_connect_data(cclosetab_menu, "activate", Close_Tab, 0, 0, 0) gtk_widget_show_all(cmenu) ' Create notebook notebook = gtk_notebook_new() g_signal_connect_data(notebook, "button-press-event", Show_Popup, 0, 0, 0) Create_Page ' Create statusbar statusbar = gtk_statusbar_new() msg_cid = gtk_statusbar_get_context_id(statusbar, "bacon") gtk_statusbar_push(statusbar, msg_cid, CONCAT$("Compiled with BaCon ", VERSION$)) ' Setup vbox vbox = gtk_vbox_new(0, 0) gtk_box_pack_start(vbox, menubar, 0, 0, 1) gtk_box_pack_start(vbox, notebook, 1, 1, 1) gtk_box_pack_start(vbox, statusbar, 0, 0, 1) ' Finalize GUI gtk_container_add(win, vbox) gtk_widget_show_all(win) ' Define some accelerator keys accel_group = gtk_accel_group_new() gtk_window_add_accel_group(win, accel_group) gtk_widget_add_accelerator(file_menu, "activate", accel_group, gdk_keyval_from_name("o"), GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE) gtk_widget_add_accelerator(save_menu, "activate", accel_group, gdk_keyval_from_name("s"), GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE) gtk_widget_add_accelerator(saveas_menu, "activate", accel_group, gdk_keyval_from_name("s"), GDK_CONTROL_MASK|GDK_SHIFT_MASK, GTK_ACCEL_VISIBLE) gtk_widget_add_accelerator(newtab_menu, "activate", accel_group, gdk_keyval_from_name("n"), GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE) gtk_widget_add_accelerator(opentab_menu, "activate", accel_group, gdk_keyval_from_name("n"), GDK_CONTROL_MASK|GDK_SHIFT_MASK, GTK_ACCEL_VISIBLE) gtk_widget_add_accelerator(closetab_menu, "activate", accel_group, gdk_keyval_from_name("t"), GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE) gtk_widget_add_accelerator(exit_menu, "activate", accel_group, gdk_keyval_from_name("q"), GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE) gtk_widget_add_accelerator(cut_menu, "activate", accel_group, gdk_keyval_from_name("x"), GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE) gtk_widget_add_accelerator(copy_menu, "activate", accel_group, gdk_keyval_from_name("c"), GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE) gtk_widget_add_accelerator(paste_menu, "activate", accel_group, gdk_keyval_from_name("v"), GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE) gtk_widget_add_accelerator(undo_menu, "activate", accel_group, gdk_keyval_from_name("z"), GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE) gtk_widget_add_accelerator(select_menu, "activate", accel_group, gdk_keyval_from_name("a"), GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE) gtk_widget_add_accelerator(find_menu, "activate", accel_group, gdk_keyval_from_name("f"), GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE) ' Get the default settings for the new page IF FILEEXISTS(CONCAT$(GETENVIRON$("HOME"), "/.bacon.txt")) THEN Load_Defaults ' Create FIND dialog find = gtk_window_new(GTK_WINDOW_TOPLEVEL) gtk_window_set_title(find, "Find term") gtk_window_set_transient_for(find, win) gtk_window_set_position(find, GTK_WIN_POS_CENTER_ON_PARENT) gtk_window_set_default_size(find, 300, 70) gtk_window_set_icon_name(find, "gtk-find") find_entry = gtk_entry_new() find_ok = gtk_button_new_from_stock("gtk-close") find_get = gtk_button_new_from_stock("gtk-find") ' Now arrange FIND widgets on window using boxes find_vbox = gtk_vbox_new(0, 0) find_hbox = gtk_hbox_new(0, 0) gtk_box_pack_start(find_vbox, find_entry, 1, 1, 1) gtk_box_pack_start(find_hbox, find_ok, 0, 0, 1) gtk_box_pack_end(find_hbox, find_get, 0, 0, 1) gtk_box_pack_start(find_vbox, find_hbox, 0, 0, 1) gtk_container_add(find, find_vbox) g_signal_connect_data(find, "delete-event", Hide_Find, 0, 0, 0) g_signal_connect_data(find_ok, "clicked", Hide_Find, 0, 0, 0) g_signal_connect_data(find_get, "clicked", Find_Term, 0, 0, 0) g_signal_connect_data(find_entry, "activate", Find_Term, 0, 0, 0) ' Callbacks for the menu items g_signal_connect_data(file_menu, "activate", Open_File, 0, 0, 0) g_signal_connect_data(save_menu, "activate", Save_File, 0, 0, 0) g_signal_connect_data(saveas_menu, "activate", Save_Fileas, 0, 0, 0) g_signal_connect_data(newtab_menu, "activate", Create_Page, 0, 0, 0) g_signal_connect_data(opentab_menu, "activate", Open_Page, 0, 0, 0) g_signal_connect_data(closetab_menu, "activate", Close_Tab, 0, 0, 0) g_signal_connect_data(exit_menu, "activate", Exit_Prog, 0, 0, 0) g_signal_connect_data(cut_menu, "activate", Cut_Text, 0, 0, 0) g_signal_connect_data(copy_menu, "activate", Copy_Text, 0, 0, 0) g_signal_connect_data(paste_menu, "activate", Paste_Text, 0, 0, 0) g_signal_connect_data(undo_menu, "activate", Undo_Action, 0, 0, 0) g_signal_connect_data(select_menu, "activate", Select_All, 0, 0, 0) g_signal_connect_data(find_menu, "activate", Start_Find, 0, 0, 0) g_signal_connect_data(indent_menu, "activate", Set_Indent, 0, 0, 0) g_signal_connect_data(linenr_menu, "activate", Set_Linenr, 0, 0, 0) g_signal_connect_data(wrap_menu, "activate", Set_Wrapmode, 0, 0, 0) g_signal_connect_data(font_menu, "activate", Select_Font, 0, 0, 0) g_signal_connect_data(color_menu, "activate", Select_Color, 0, 0, 0) g_signal_connect_data(syntax_menu, "activate", Get_Syntax, 0, 0, 0) g_signal_connect_data(about_menu, "activate", Show_Info, 0, 0, 0) 'Endless mainloop gtk_main END SUB '------------------------------------------------------------------------------------------------------------