From 0a8a4bca03824b41305ae0381e3689bb701bcdbb Mon Sep 17 00:00:00 2001 From: John Paul Wohlscheid Date: Tue, 24 Feb 2026 11:40:42 -0500 Subject: [PATCH] first working version --- doc.bas | 15 ++ doc.bi | 11 ++ main | Bin 0 -> 85864 bytes main.bas | 406 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 432 insertions(+) create mode 100644 doc.bas create mode 100644 doc.bi create mode 100755 main create mode 100644 main.bas diff --git a/doc.bas b/doc.bas new file mode 100644 index 0000000..d91d835 --- /dev/null +++ b/doc.bas @@ -0,0 +1,15 @@ +' doc.bas +#include once "doc.bi" + +sub Doc_Init( byref d as DocState ) + d.path = "" + d.modified = 0 +end sub + +sub Doc_SetPath( byref d as DocState, byref p as string ) + d.path = p +end sub + +sub Doc_SetModified( byref d as DocState, byval m as integer ) + d.modified = iif(m <> 0, 1, 0) +end sub diff --git a/doc.bi b/doc.bi new file mode 100644 index 0000000..0aaa568 --- /dev/null +++ b/doc.bi @@ -0,0 +1,11 @@ +' doc.bi +#pragma once + +type DocState + path as string + modified as integer +end type + +declare sub Doc_Init( byref d as DocState ) +declare sub Doc_SetPath( byref d as DocState, byref p as string ) +declare sub Doc_SetModified( byref d as DocState, byval m as integer ) diff --git a/main b/main new file mode 100755 index 0000000000000000000000000000000000000000..e4b6adf52aa21fae6b74bf8c829e05487b3b4f0f GIT binary patch literal 85864 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

Cc`4wxm|qrqXQsXPNS1ZJ2( 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

-6~q+AJB-n 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 literal 0 HcmV?d00001 diff --git a/main.bas b/main.bas new file mode 100644 index 0000000..be31bba --- /dev/null +++ b/main.bas @@ -0,0 +1,406 @@ +' main.bas +#inclib "gtk-3" + +#define __USE_GTK3__ +#include once "gtk/gtk.bi" + +#include once "doc.bi" + +' ---------- Globals ---------- +dim shared gWin as GtkWidget ptr +dim shared gView as GtkWidget ptr +dim shared gBuf as GtkTextBuffer ptr +dim shared gStatus as GtkWidget ptr +dim shared gStatusId as guint +dim shared gDoc as DocState + +const APP_NAME = "FREEnote" +const APP_VERSION = "0.1" + +' ---------- Helpers ---------- +function AppTitle() as string + dim appBase as string = APP_NAME + dim docLabel as string + + if gDoc.path <> "" then + docLabel = gDoc.path + else + docLabel = "Untitled" + end if + + if gDoc.modified <> 0 then + return appBase & " - " & docLabel & " *" + else + return appBase & " - " & docLabel + end if +end function + +declare function OnDeleteEvent cdecl (byval widget as GtkWidget ptr, byval event as GdkEvent ptr, byval userData as gpointer) as gboolean +declare function SaveCurrent() as integer + +sub UpdateTitle() + gtk_window_set_title(GTK_WINDOW(gWin), AppTitle()) +end sub + +sub UpdateStatus() + ' Line/Col from insert mark + dim insMark as GtkTextMark ptr = gtk_text_buffer_get_insert(gBuf) + dim it as GtkTextIter + gtk_text_buffer_get_iter_at_mark(gBuf, @it, insMark) + + dim ln as integer = gtk_text_iter_get_line(@it) + 1 + dim col as integer = gtk_text_iter_get_line_offset(@it) + 1 + + dim msg as string = "Ln " & str(ln) & ", Col " & str(col) & _ + iif(gDoc.modified<>0, " (Modified)", " (Saved)") + + gtk_statusbar_pop(GTK_STATUSBAR(gStatus), gStatusId) + gtk_statusbar_push(GTK_STATUSBAR(gStatus), gStatusId, msg) +end sub + +sub SetBufferText(byref s as string) + gtk_text_buffer_set_text(gBuf, s, len(s)) + ' Clear modified flag after programmatic set + gtk_text_buffer_set_modified(gBuf, FALSE) + Doc_SetModified(gDoc, 0) + UpdateTitle() + UpdateStatus() +end sub + +function GetBufferText() as string + dim a as GtkTextIter, b as GtkTextIter + gtk_text_buffer_get_bounds(gBuf, @a, @b) + + dim p as zstring ptr = gtk_text_buffer_get_text(gBuf, @a, @b, TRUE) + dim textOut as string = *p + g_free(p) + + return textOut +end function + +' returns: 0 cancel, 1 discard, 2 save +function ConfirmDiscardChanges() as integer + if gDoc.modified = 0 then return 1 + + dim dlg as GtkWidget ptr + dlg = gtk_message_dialog_new( _ + GTK_WINDOW(gWin), _ + GTK_DIALOG_MODAL, _ + GTK_MESSAGE_WARNING, _ + GTK_BUTTONS_NONE, _ + "This document has unsaved changes." _ + ) + + gtk_dialog_add_button(GTK_DIALOG(dlg), "Cancel", GTK_RESPONSE_CANCEL) + gtk_dialog_add_button(GTK_DIALOG(dlg), "Discard", GTK_RESPONSE_REJECT) + gtk_dialog_add_button(GTK_DIALOG(dlg), "Save", GTK_RESPONSE_ACCEPT) + + gtk_message_dialog_format_secondary_text( _ + GTK_MESSAGE_DIALOG(dlg), _ + "Do you want to save your changes before continuing?" _ + ) + + dim resp as integer = gtk_dialog_run(GTK_DIALOG(dlg)) + gtk_widget_destroy(dlg) + + select case resp + case GTK_RESPONSE_ACCEPT + return 2 + case GTK_RESPONSE_REJECT + return 1 + case else + return 0 + end select +end function + +function WriteFile(byref path as string, byref contents as string) as integer + dim f as integer = freefile() + if open(path for output as #f) <> 0 then return 0 + print #f, contents; + close #f + return 1 +end function + +function ReadFile(byref path as string, byref outText as string) as integer + dim f as integer = freefile() + if open(path for input as #f) <> 0 then return 0 + + outText = "" + while not eof(f) + dim oneLine as string + line input #f, oneLine + if outText <> "" then outText &= chr(10) + outText &= oneLine + wend + + close #f + return 1 +end function + +function OnDeleteEvent cdecl (byval widget as GtkWidget ptr, byval event as GdkEvent ptr, byval userData as gpointer) as gboolean + dim r as integer = ConfirmDiscardChanges() + if r = 0 then return TRUE + + if r = 2 then + if SaveCurrent() = 0 then return TRUE + end if + + return FALSE +end function + +function ChooseOpenPath() as string + dim dlg as GtkWidget ptr + dlg = gtk_file_chooser_dialog_new( _ + "Open File", _ + GTK_WINDOW(gWin), _ + GTK_FILE_CHOOSER_ACTION_OPEN, _ + "_Cancel", GTK_RESPONSE_CANCEL, _ + "_Open", GTK_RESPONSE_ACCEPT, _ + NULL _ + ) + + dim result as string = "" + if gtk_dialog_run(GTK_DIALOG(dlg)) = GTK_RESPONSE_ACCEPT then + dim p as zstring ptr = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dlg)) + if p <> 0 then + result = *p + g_free(p) + end if + end if + gtk_widget_destroy(dlg) + return result +end function + +function ChooseSavePath(byref suggested as string) as string + dim dlg as GtkWidget ptr + dlg = gtk_file_chooser_dialog_new( _ + "Save File", _ + GTK_WINDOW(gWin), _ + GTK_FILE_CHOOSER_ACTION_SAVE, _ + "_Cancel", GTK_RESPONSE_CANCEL, _ + "_Save", GTK_RESPONSE_ACCEPT, _ + NULL _ + ) + + gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dlg), TRUE) + + if suggested <> "" then + gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dlg), suggested) + end if + + dim result as string = "" + if gtk_dialog_run(GTK_DIALOG(dlg)) = GTK_RESPONSE_ACCEPT then + dim p as zstring ptr = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dlg)) + if p <> 0 then + result = *p + g_free(p) + end if + end if + gtk_widget_destroy(dlg) + return result +end function + +function SaveToPath(byref path as string) as integer + dim txt as string = GetBufferText() + if WriteFile(path, txt) = 0 then + dim errDlg as GtkWidget ptr + errDlg = gtk_message_dialog_new( _ + GTK_WINDOW(gWin), GTK_DIALOG_MODAL, _ + GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _ + "Could not save file." _ + ) + gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(errDlg), path) + gtk_dialog_run(GTK_DIALOG(errDlg)) + gtk_widget_destroy(errDlg) + return 0 + end if + + Doc_SetPath(gDoc, path) + gtk_text_buffer_set_modified(gBuf, FALSE) + Doc_SetModified(gDoc, 0) + UpdateTitle() + UpdateStatus() + return 1 +end function + +function SaveCurrent() as integer + if gDoc.path = "" then + dim chosen as string = ChooseSavePath("") + if chosen = "" then return 0 + return SaveToPath(chosen) + else + return SaveToPath(gDoc.path) + end if +end function + +' ---------- Callbacks ---------- +sub OnBufferModifiedChanged cdecl (byval buf as GtkTextBuffer ptr, byval userData as gpointer) + dim m as gboolean = gtk_text_buffer_get_modified(buf) + Doc_SetModified(gDoc, iif(m, 1, 0)) + UpdateTitle() + UpdateStatus() +end sub + +sub OnMarkSet cdecl (byval buf as GtkTextBuffer ptr, byval iter as GtkTextIter ptr, byval mark as GtkTextMark ptr, byval userData as gpointer) + UpdateStatus() +end sub + +sub OnNew cdecl (byval widget as GtkWidget ptr, byval userData as gpointer) + dim r as integer = ConfirmDiscardChanges() + if r = 0 then exit sub + if r = 2 then + if SaveCurrent() = 0 then exit sub + end if + + Doc_SetPath(gDoc, "") + SetBufferText("") +end sub + +sub OnOpen cdecl (byval widget as GtkWidget ptr, byval userData as gpointer) + dim r as integer = ConfirmDiscardChanges() + if r = 0 then exit sub + if r = 2 then + if SaveCurrent() = 0 then exit sub + end if + + dim path as string = ChooseOpenPath() + if path = "" then exit sub + + dim txt as string + if ReadFile(path, txt) = 0 then + dim errDlg as GtkWidget ptr + errDlg = gtk_message_dialog_new( _ + GTK_WINDOW(gWin), GTK_DIALOG_MODAL, _ + GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _ + "Could not open file." _ + ) + gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(errDlg), path) + gtk_dialog_run(GTK_DIALOG(errDlg)) + gtk_widget_destroy(errDlg) + exit sub + end if + + Doc_SetPath(gDoc, path) + SetBufferText(txt) +end sub + +sub OnSave cdecl (byval widget as GtkWidget ptr, byval userData as gpointer) + SaveCurrent() +end sub + +sub OnSaveAs cdecl (byval widget as GtkWidget ptr, byval userData as gpointer) + dim suggested as string = gDoc.path + dim chosen as string = ChooseSavePath(suggested) + if chosen = "" then exit sub + SaveToPath(chosen) +end sub + +sub OnExit cdecl (byval widget as GtkWidget ptr, byval userData as gpointer) + gtk_widget_destroy(gWin) +end sub + +sub OnAbout cdecl (byval widget as GtkWidget ptr, byval userData as gpointer) + dim dlg as GtkWidget ptr + dlg = gtk_message_dialog_new( _ + GTK_WINDOW(gWin), _ + GTK_DIALOG_MODAL, _ + GTK_MESSAGE_INFO, _ + GTK_BUTTONS_OK, _ + APP_NAME & " " & APP_VERSION _ + ) + + gtk_message_dialog_format_secondary_text( _ + GTK_MESSAGE_DIALOG(dlg), _ + "A lightweight text editor written in FreeBASIC + GTK3." & chr(10) & _ + "Created by John Paul Wohlscheid and ChatGPT." _ + ) + + gtk_dialog_run(GTK_DIALOG(dlg)) + gtk_widget_destroy(dlg) +end sub + +' ---------- UI Construction ---------- +function MakeMenuBar() as GtkWidget ptr + dim menubar as GtkWidget ptr = gtk_menu_bar_new() + + ' File menu + dim fileItem as GtkWidget ptr = gtk_menu_item_new_with_label("File") + dim fileMenu as GtkWidget ptr = gtk_menu_new() + + dim miNew as GtkWidget ptr = gtk_menu_item_new_with_label("New") + dim miOpen as GtkWidget ptr = gtk_menu_item_new_with_label("Open") + dim miSave as GtkWidget ptr = gtk_menu_item_new_with_label("Save") + dim miSaveA as GtkWidget ptr = gtk_menu_item_new_with_label("Save As") + dim sep1 as GtkWidget ptr = gtk_separator_menu_item_new() + dim miExit as GtkWidget ptr = gtk_menu_item_new_with_label("Exit") + + gtk_menu_shell_append(GTK_MENU_SHELL(fileMenu), miNew) + gtk_menu_shell_append(GTK_MENU_SHELL(fileMenu), miOpen) + gtk_menu_shell_append(GTK_MENU_SHELL(fileMenu), miSave) + gtk_menu_shell_append(GTK_MENU_SHELL(fileMenu), miSaveA) + gtk_menu_shell_append(GTK_MENU_SHELL(fileMenu), sep1) + gtk_menu_shell_append(GTK_MENU_SHELL(fileMenu), miExit) + + gtk_menu_item_set_submenu(GTK_MENU_ITEM(fileItem), fileMenu) + gtk_menu_shell_append(GTK_MENU_SHELL(menubar), fileItem) + + g_signal_connect(miNew, "activate", G_CALLBACK(@OnNew), NULL) + g_signal_connect(miOpen, "activate", G_CALLBACK(@OnOpen), NULL) + g_signal_connect(miSave, "activate", G_CALLBACK(@OnSave), NULL) + g_signal_connect(miSaveA,"activate", G_CALLBACK(@OnSaveAs),NULL) + g_signal_connect(miExit, "activate", G_CALLBACK(@OnExit), NULL) + + ' Help menu + dim helpItem as GtkWidget ptr = gtk_menu_item_new_with_label("Help") + dim helpMenu as GtkWidget ptr = gtk_menu_new() + dim miAbout as GtkWidget ptr = gtk_menu_item_new_with_label("About") + + gtk_menu_shell_append(GTK_MENU_SHELL(helpMenu), miAbout) + gtk_menu_item_set_submenu(GTK_MENU_ITEM(helpItem), helpMenu) + gtk_menu_shell_append(GTK_MENU_SHELL(menubar), helpItem) + + g_signal_connect(miAbout, "activate", G_CALLBACK(@OnAbout), NULL) + + return menubar +end function + +' ---------- Main ---------- +gtk_init(NULL, NULL) + +Doc_Init(gDoc) + +gWin = gtk_window_new(GTK_WINDOW_TOPLEVEL) +gtk_window_set_default_size(GTK_WINDOW(gWin), 900, 600) +UpdateTitle() + +g_signal_connect(gWin, "delete-event", G_CALLBACK(@OnDeleteEvent), NULL) + +dim vbox as GtkWidget ptr = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0) +gtk_container_add(GTK_CONTAINER(gWin), vbox) + +dim menubar as GtkWidget ptr = MakeMenuBar() +gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0) + +' Scrolled editor +dim scroller as GtkWidget ptr = gtk_scrolled_window_new(NULL, NULL) +gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroller), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC) +gtk_box_pack_start(GTK_BOX(vbox), scroller, TRUE, TRUE, 0) + +gView = gtk_text_view_new() +gtk_container_add(GTK_CONTAINER(scroller), gView) + +gBuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gView)) + +' Statusbar +gStatus = gtk_statusbar_new() +gStatusId = gtk_statusbar_get_context_id(GTK_STATUSBAR(gStatus), "cursor") +gtk_box_pack_end(GTK_BOX(vbox), gStatus, FALSE, FALSE, 0) + +' Buffer signals for modified + cursor status +g_signal_connect(gBuf, "modified-changed", G_CALLBACK(@OnBufferModifiedChanged), NULL) +g_signal_connect(gBuf, "mark-set", G_CALLBACK(@OnMarkSet), NULL) + +UpdateStatus() + +gtk_widget_show_all(gWin) +gtk_main()