From bc108fd73ab4ab629699b4705fdb887cba8eedf5 Mon Sep 17 00:00:00 2001 From: Scott Duensing Date: Thu, 26 Jan 2023 21:35:14 -0600 Subject: [PATCH] Start of code editor. --- CMakeLists.txt | 1 + include/editor.h | 30 ++++++ include/scintillaHeaders.h | 4 + src/editor.c | 216 +++++++++++++++++++++++++++++++++++++ src/joeydev.c | 10 ++ src/utils.c | 10 +- src/vector.c | 4 +- ui/Editor.glade | 189 ++++++++++++++++++++++++++++++++ ui/JoeyDev.glade | 15 +++ ui/Vector.glade | 2 +- ui/joeydev.gresource.xml | 1 + 11 files changed, 475 insertions(+), 7 deletions(-) create mode 100644 include/editor.h create mode 100644 src/editor.c create mode 100644 ui/Editor.glade diff --git a/CMakeLists.txt b/CMakeLists.txt index c45cd79..0294068 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,6 +53,7 @@ set(SOURCE_FILES src/project.c src/ssh.c src/http.c + src/editor.c ) configure_file(include/config.h.in config.h) diff --git a/include/editor.h b/include/editor.h new file mode 100644 index 0000000..74f7e77 --- /dev/null +++ b/include/editor.h @@ -0,0 +1,30 @@ +/* + * JoeyDev + * Copyright (C) 2018-2023 Scott Duensing + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. +*/ + + +#ifndef EDITOR_H +#define EDITOR_H + + +void winEditorCreate(void); + + +#endif // EDITOR_H diff --git a/include/scintillaHeaders.h b/include/scintillaHeaders.h index f04f17b..0832d12 100644 --- a/include/scintillaHeaders.h +++ b/include/scintillaHeaders.h @@ -32,4 +32,8 @@ #include "Lexilla.h" +#define SSM(m, w, l) scintilla_send_message(self->sci, m, w, l) +#define MARGIN_SCRIPT_FOLD_INDEX 1 + + #endif //SCINTILLAHEADERS_H diff --git a/src/editor.c b/src/editor.c new file mode 100644 index 0000000..4890364 --- /dev/null +++ b/src/editor.c @@ -0,0 +1,216 @@ +/* + * JoeyDev + * Copyright (C) 2018-2023 Scott Duensing + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. +*/ + + +#include "common.h" +#include "editor.h" +#include "utils.h" +#include "scintillaHeaders.h" + + +typedef struct EditorDataS { + WindowDataT windowData; + GtkWidget *boxForEditor; + GtkWidget *statusBar; + GtkWidget *editor; + ScintillaObject *sci; + void *pLexer; + int id; + int statusBarId; +} EditorDataT; + + +static int _nextEditorId = 0; + + +EVENT void editorEditorNotify(GtkWidget *sciWidget, gint ctrlID, struct SCNotification *notifyData, gpointer userData); +EVENT gboolean winEditorClose(GtkWidget *object, gpointer userData); +static void winEditorDelete(gpointer userData); + + + +EVENT void editorEditorNotify(GtkWidget *sciWidget, gint ctrlID, struct SCNotification *notifyData, gpointer userData) { + EditorDataT *self = (EditorDataT *)userData; + int lineNumber = (int)SSM(SCI_LINEFROMPOSITION, (uptr_t)notifyData->position, (sptr_t)0); + + (void)sciWidget; + (void)ctrlID; + + switch (notifyData->nmhdr.code) { + case SCN_MODIFIED: + if (notifyData->modificationType & SC_MOD_INSERTTEXT || notifyData->modificationType & SC_MOD_DELETETEXT) { + // Mark text dirty. SCN_SAVEPOINTLEFT isn't being reliable. + utilSetDirty((WindowDataT *)self, TRUE); + } + break; + + case SCN_MARGINCLICK: + switch (notifyData->margin) { + case MARGIN_SCRIPT_FOLD_INDEX: + SSM(SCI_TOGGLEFOLD, lineNumber, (sptr_t)0); + break; + } + break; + + } +} + + + EVENT gboolean winEditorClose(GtkWidget *object, gpointer userData) { + // userData is not reliable due to menuVectorFileClose and util indirectly calling us. + EditorDataT *self = (EditorDataT *)utilGetWindowData(object); + + (void)userData; + + if (self->windowData.isDirty == TRUE) { + if (utilQuestionDialog(self->windowData.window, "Exit", "You have unsaved changes. Exit?")) { + winEditorDelete(self); + return FALSE; + } + return TRUE; + } + + winEditorDelete(self); + return FALSE; +} + + +void winEditorCreate(void) { + EditorDataT *self; + char *widgetNames[] = { + "winEditor", + "boxEditorForEditor", + "statusEditor", + NULL + }; + GtkWidget **widgets[] = { + NULL, + NULL, + NULL + }; + + // Set up instance data. + self = NEW(EditorDataT); + self->windowData.closeWindow = winEditorClose; + + // Load widgets from XML. + widgets[0] = &self->windowData.window; + widgets[1] = &self->boxForEditor; + widgets[2] = &self->statusBar; + utilGetWidgetsFromMemory("/com/kangaroopunch/joeydev/Editor.glade", widgetNames, widgets, self); + + // Register window. + utilWindowRegister(self); + + // Get status bar context ID. + self->statusBarId = gtk_statusbar_get_context_id(GTK_STATUSBAR(self->statusBar), "JoeyDev"); + + // Create Scintilla editor. + self->editor = scintilla_new(); + self->sci = SCINTILLA(self->editor); + self->id = _nextEditorId++; + scintilla_set_id(self->sci, self->id); + gtk_widget_set_halign(self->editor, GTK_ALIGN_FILL); + gtk_widget_set_valign(self->editor, GTK_ALIGN_FILL); + gtk_widget_set_hexpand(self->editor, TRUE); + gtk_widget_set_vexpand(self->editor, TRUE); + gtk_box_set_child_packing(GTK_BOX(self->boxForEditor), self->editor, TRUE, TRUE, 0, GTK_PACK_START); + gtk_container_add(GTK_CONTAINER(self->boxForEditor), self->editor); + + // Configure editor. + SSM(SCI_SETCODEPAGE, SC_CP_UTF8, 0); + SSM(SCI_SETIMEINTERACTION, SC_IME_WINDOWED, 0); + SSM(SCI_STYLESETCHARACTERSET, STYLE_DEFAULT, SC_CHARSET_DEFAULT); + SSM(SCI_STYLESETFONT, STYLE_DEFAULT, (sptr_t)"Monospace"); + SSM(SCI_STYLESETSIZEFRACTIONAL, STYLE_DEFAULT, 11 * SC_FONT_SIZE_MULTIPLIER); + SSM(SCI_STYLESETFORE, STYLE_DEFAULT, 0xFFFFFF); + SSM(SCI_STYLESETBACK, STYLE_DEFAULT, 0); + SSM(SCI_STYLECLEARALL, 0, 0); + SSM(SCI_SETTABWIDTH, 3, 0); + //SSM(SCI_SETEOLMODE, SC_EOL_CR, 0); + SSM(SCI_SETMARGINWIDTHN, 0, (int)SSM(SCI_TEXTWIDTH, STYLE_LINENUMBER, (sptr_t)"_99999")); + SSM(SCI_SETMARGINWIDTHN, 1, 16); + SSM(SCI_SETWRAPMODE, SC_WRAP_NONE, 0); + SSM(SCI_SETCARETSTYLE, CARETSTYLE_BLOCK | CARETSTYLE_OVERSTRIKE_BLOCK, 0); + SSM(SCI_SETCARETFORE, 0x00ffff, 0); + SSM(SCI_STYLESETBACK, STYLE_LINENUMBER, 0x222222); + + // Add lexer for language support. + self->pLexer = CreateLexer("cpp"); + SSM(SCI_SETILEXER, 0, (sptr_t)self->pLexer); + + /* + #define SCE_C_DEFAULT 0 + #define SCE_C_COMMENT 1 + #define SCE_C_COMMENTLINE 2 + #define SCE_C_COMMENTDOC 3 + #define SCE_C_NUMBER 4 + #define SCE_C_WORD 5 + #define SCE_C_STRING 6 + #define SCE_C_CHARACTER 7 + #define SCE_C_UUID 8 + #define SCE_C_PREPROCESSOR 9 + #define SCE_C_OPERATOR 10 + #define SCE_C_IDENTIFIER 11 + #define SCE_C_STRINGEOL 12 + #define SCE_C_VERBATIM 13 + #define SCE_C_REGEX 14 + #define SCE_C_COMMENTLINEDOC 15 + #define SCE_C_WORD2 16 + #define SCE_C_COMMENTDOCKEYWORD 17 + #define SCE_C_COMMENTDOCKEYWORDERROR 18 + #define SCE_C_GLOBALCLASS 19 + #define SCE_C_STRINGRAW 20 + #define SCE_C_TRIPLEVERBATIM 21 + #define SCE_C_HASHQUOTEDSTRING 22 + #define SCE_C_PREPROCESSORCOMMENT 23 + #define SCE_C_PREPROCESSORCOMMENTDOC 24 + #define SCE_C_USERLITERAL 25 + #define SCE_C_TASKMARKER 26 + #define SCE_C_ESCAPESEQUENCE 27 + */ + + SSM(SCI_STYLESETFORE, SCE_C_PREPROCESSOR, 0x0080ff); + SSM(SCI_STYLESETFORE, SCE_C_COMMENT, 0x00FF00); + SSM(SCI_STYLESETFORE, SCE_C_COMMENTLINE, 0x00FF00); + SSM(SCI_STYLESETFORE, SCE_C_NUMBER, 0xFFFF00); + SSM(SCI_STYLESETFORE, SCE_C_WORD, 0xFF0000); + SSM(SCI_STYLESETFORE, SCE_C_STRING, 0xFF00FF); + SSM(SCI_STYLESETBOLD, SCE_C_OPERATOR, 1); + + // Connect editor to our code. + g_signal_connect(G_OBJECT(self->editor), "sci-notify", G_CALLBACK(editorEditorNotify), self); + + // Show window. + gtk_widget_show_all(self->windowData.window); +} + + +static void winEditorDelete(gpointer userData) { + EditorDataT *self = (EditorDataT *)userData; + + // Scintilla keeps sending events after we delete things it expects to still exist. Prevent that. + g_signal_handlers_disconnect_by_func(G_OBJECT(self->editor), G_CALLBACK(editorEditorNotify), self); + + utilWindowUnRegister(userData); + + DEL(self); +} diff --git a/src/joeydev.c b/src/joeydev.c index 5e1646b..b3220f4 100644 --- a/src/joeydev.c +++ b/src/joeydev.c @@ -25,6 +25,7 @@ #include "common.h" #include "utils.h" #include "project.h" +#include "editor.h" #include "vector.h" #include "joeydev.h" @@ -33,6 +34,7 @@ static GtkWidget *_winJoeyDev = NULL; EVENT void toolJoeyDevAboutClicked(GtkWidget *widget, gpointer userData); +EVENT void toolJoeyDevEditorClicked(GtkWidget *widget, gpointer userData); EVENT void toolJoeyDevProjectClicked(GtkWidget *widget, gpointer userData); EVENT void toolJoeyDevQuitClicked(GtkWidget *widget, gpointer userData); EVENT void toolJoeyDevVectorClicked(GtkWidget *widget, gpointer userData); @@ -64,6 +66,14 @@ EVENT void toolJoeyDevAboutClicked(GtkWidget *widget, gpointer userData) { } +EVENT void toolJoeyDevEditorClicked(GtkWidget *widget, gpointer userData) { + (void)widget; + (void)userData; + + winEditorCreate(); +} + + EVENT void toolJoeyDevProjectClicked(GtkWidget *widget, gpointer userData) { (void)widget; (void)userData; diff --git a/src/utils.c b/src/utils.c index 581d71c..602ab7c 100644 --- a/src/utils.c +++ b/src/utils.c @@ -193,7 +193,7 @@ gboolean utilFileSaveAs(WindowDataT *self, char *extension, char *what) { GtkWidget *dialog; GtkFileFilter *filter; gboolean result = FALSE; - char *files = utilCreateString("%s Files", what); + char *files = utilCreateString("%s Files", what); int x; dialog = gtk_file_chooser_dialog_new("Save As", @@ -442,11 +442,14 @@ void utilWindowRegister(gpointer windowData) { w->title = strdup(gtk_window_get_title(GTK_WINDOW(w->window))); hmput(_windowList, w->window, windowData); + debug("Window Registered: %d\n", hmlen(_windowList)); } int utilWindowsCloseAll(void) { WindowDataT *w; + + debug("Windows Left Open: %d\n", hmlen(_windowList)); while (hmlen(_windowList) > 0) { w = (WindowDataT *)_windowList[0].value; if (w->closeWindow(w->window, w) == TRUE) { @@ -469,10 +472,11 @@ int utilWindowsOpen(void) { gboolean utilWindowUnRegister(gpointer windowData) { - int result; + int result = 0; + WindowDataT *w = (WindowDataT *)windowData; - WindowDataT *w = (WindowDataT *)windowData; result = hmdel(_windowList, w->window); + debug("Window Unregistered: %d\n", hmlen(_windowList)); DEL(w->filename); DEL(w->title); diff --git a/src/vector.c b/src/vector.c index 065086a..900d28a 100644 --- a/src/vector.c +++ b/src/vector.c @@ -42,8 +42,6 @@ #define RENDER_TIMEOUT 5 // In seconds -#define SSM(m, w, l) scintilla_send_message(self->sci, m, w, l) -#define MARGIN_SCRIPT_FOLD_INDEX 1 #define MARKER_ERROR_ARROW 0 #define MARKER_ERROR_HIGHLIGHT 1 #define PREVIEW_WIDTH 640 @@ -1383,7 +1381,7 @@ void winVectorCreate(char *filename) { "boxVectorForEditor", "drawVectorImage", "fileVectorTraceImage", - "status", + "statusVector", NULL }; GtkWidget **widgets[] = { diff --git a/ui/Editor.glade b/ui/Editor.glade new file mode 100644 index 0000000..8ffcb7c --- /dev/null +++ b/ui/Editor.glade @@ -0,0 +1,189 @@ + + + + + + False + Editor + 640 + 480 + accessories-text-editor + + + + True + False + vertical + + + True + False + + + True + False + _File + True + + + True + False + + + True + False + True + + + + + True + False + True + + + + + True + False + True + + + + + True + False + True + + + + + True + False + + + + + True + False + True + + + + + + + + + True + False + _Edit + True + + + True + False + + + True + False + True + + + + + True + False + True + + + + + True + False + True + + + + + True + False + True + + + + + + + + + True + False + _View + True + + + + + True + False + _Help + True + + + True + False + + + True + False + True + + + + + + + + + False + True + 0 + + + + + True + False + vertical + + + + + + True + True + 1 + + + + + True + False + 10 + 10 + 6 + 6 + vertical + 2 + + + False + True + 2 + + + + + + diff --git a/ui/JoeyDev.glade b/ui/JoeyDev.glade index 808d05c..2c672e7 100644 --- a/ui/JoeyDev.glade +++ b/ui/JoeyDev.glade @@ -69,6 +69,21 @@ Author: Scott Duensing True + + + True + False + Editor + Editor + True + accessories-text-editor + + + + False + True + + True diff --git a/ui/Vector.glade b/ui/Vector.glade index e858e43..fdde12a 100644 --- a/ui/Vector.glade +++ b/ui/Vector.glade @@ -461,7 +461,7 @@ Author: Scott Duensing - + True False 10 diff --git a/ui/joeydev.gresource.xml b/ui/joeydev.gresource.xml index e740fbf..e513d51 100644 --- a/ui/joeydev.gresource.xml +++ b/ui/joeydev.gresource.xml @@ -4,6 +4,7 @@ JoeyDev.glade Project.glade BuildServer.glade + Editor.glade Vector.glade Logo.png