From b3fd82bed361c508688ce8b083fd7f96aa5d8e5f Mon Sep 17 00:00:00 2001 From: Scott Duensing Date: Mon, 19 Dec 2022 18:01:43 -0600 Subject: [PATCH] Project load/save/edit working. --- include/utils.h | 1 + src/project.c | 238 ++++++++++++++++++++++++++++++++--------------- src/utils.c | 36 +++++++ src/vector.c | 19 +--- ui/Project.glade | 1 + 5 files changed, 203 insertions(+), 92 deletions(-) diff --git a/include/utils.h b/include/utils.h index 097c977..284ff34 100644 --- a/include/utils.h +++ b/include/utils.h @@ -32,6 +32,7 @@ char *utilCreateStringVArgs(char *format, va_list args); void utilEnsureBufferSize(unsigned char **buffer, int *length, int wanted); gboolean utilFileExists(char *filename); gboolean utilFileOpen(WindowDataT *self, char *extension, char *what); +gboolean utilFileSaveAs(WindowDataT *self, char *extension, char *what); WindowDataT *utilGetWindowData(GtkWidget *window); gboolean utilGetWidgetsFromMemory(char *resource, char *name[], GtkWidget **widgets[], gpointer userData); gboolean utilQuestionDialog(GtkWidget *parent, char *title, char *question); diff --git a/src/project.c b/src/project.c index d704be8..974798d 100644 --- a/src/project.c +++ b/src/project.c @@ -29,6 +29,12 @@ #include "utils.h" +enum ProjectColumnsE { + COL_FILENAME = 0, + COL_COUNT +}; +typedef enum ProjectColumnsE ProjectColumnsT; + enum ProjectSectionTypeE { SECTION_HEADER = 0, SECTION_CODE, @@ -52,21 +58,27 @@ typedef struct ProjectDataS { char *filename; } ProjectDataT; +typedef struct SectionDataS { + char *name; + char *extension; +} SectionDataT; -static char *_SectionName[] = { - "Header", - "Code", - "Bitmap", - "Stencil", - "Vector", - "Sound", - "Music", - "Raw Data", - "Cooked Data", - NULL + +static SectionDataT _sectionData[] = { + { "Header", "*.h" }, + { "Code", "*.c" }, + { "Bitmap", "*.img" }, + { "Stencil", "*.stn" }, + { "Vector", "*.vic" }, + { "Sound", "*.snd" }, + { "Music", "*.mod" }, + { "Raw Data", "*.raw" }, + { "Cooked Data", NULL }, + { NULL, NULL } }; +static void addToTree(ProjectDataT *self, char *filename); static void loadProject(ProjectDataT *self); EVENT void menuProjectFileNew(GtkWidget *object, gpointer userData); EVENT void menuProjectFileOpen(GtkWidget *object, gpointer userData); @@ -83,17 +95,41 @@ EVENT gboolean winProjectClose(GtkWidget *object, gpointer userData); static void winProjectDelete(gpointer userData); -static void loadProject(ProjectDataT *self) { - FILE *in = NULL; - char *line = NULL; - size_t len = 0; - size_t count = 0; - int16_t extension; - int end; +static void addToTree(ProjectDataT *self, char *filename) { + ProjectSectionTypeT section; char temp[4]; GtkTreeIter iterParent; GtkTreeIter iter; - ProjectSectionTypeT section; + int fileLen; + int extLen; + + // Is it long enough? + if (strlen(filename) > 2) { + // Find proper section. + for (section = 0; section < SECTION_COUNT; section++) { + if (_sectionData[section].extension != NULL) { + // Compare last two bytes of filename with extension - it's enough to differentiate them and allows for ".c" and ".h". + fileLen = strlen(filename) - 1; + extLen = strlen(_sectionData[section].extension) - 1; + if (filename[fileLen - 1] == _sectionData[section].extension[extLen - 1] && filename[fileLen] == _sectionData[section].extension[extLen]) { + snprintf(temp, 4, "%d", section); + gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(self->storeProject), &iterParent, temp); + gtk_tree_store_append(self->storeProject, &iter, &iterParent); + gtk_tree_store_set(self->storeProject, &iter, COL_FILENAME, filename, -1); + //***TODO*** Need to store extra RAW data somewhere. + break; + } + } + } + } +} + + +static void loadProject(ProjectDataT *self) { + FILE *in = NULL; + char *line = NULL; + size_t len = 0; + size_t count = 0; in = fopen(self->windowData.filename, "rt"); if (in != NULL) { @@ -105,57 +141,7 @@ static void loadProject(ProjectDataT *self) { break; default: // Project Data - // Are we reading single filenames? - // Is it long enough? - if (strlen(line) > 5) { - // Put last three bytes - the extension - into a short int so we can use it with switch. - end = (int)strlen(line) - 1; - extension = (line[end - 2] << 16) + (line[end - 1] << 8) + line[end]; - //debug("%s - %d\n", line, extension); - switch (extension) { - case 11880: // h - section = SECTION_HEADER; - break; - - case 11875: // c - section = SECTION_CODE; - break; - - case 28007: // img - section = SECTION_BITMAP; - break; - - case 29806: // stn - section = SECTION_STENCIL; - break; - - case 26979: // vic - section = SECTION_VECTOR; - break; - - case 28260: // snd - section = SECTION_SOUND; - break; - - case 28516: // mod - section = SECTION_MUSIC; - break; - - case 24951: // raw - section = SECTION_RAW_DATA; - break; - - default: - section = SECTION_COUNT; - break; - } - } - if (section < SECTION_COUNT) { - snprintf(temp, 4, "%d", section); - gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(self->storeProject), &iterParent, temp); - gtk_tree_store_append(self->storeProject, &iter, &iterParent); - gtk_tree_store_set(self->storeProject, &iter, 0, line, -1); - } + addToTree(self, line); break; } count++; @@ -178,6 +164,8 @@ EVENT void menuProjectFileNew(GtkWidget *object, gpointer userData) { EVENT void menuProjectFileOpen(GtkWidget *object, gpointer userData) { ProjectDataT *self = (ProjectDataT *)userData; + (void)object; + if (utilFileOpen((WindowDataT *)userData, "*.joe", "Project")) { loadProject(self); } @@ -185,12 +173,55 @@ EVENT void menuProjectFileOpen(GtkWidget *object, gpointer userData) { EVENT void menuProjectFileSave(GtkWidget *object, gpointer userData) { + ProjectDataT *self = (ProjectDataT *)userData; + FILE *out = NULL; + GtkTreeIter iter; + GtkTreeIter child; + char *temp; + (void)object; + + // Do we need to save? + if (self->windowData.isDirty == TRUE) { + + // Do we have a filename? If not, kick 'em to SaveAs. + if (self->windowData.filename == NULL) { + menuProjectFileSaveAs(object, userData); + return; + } + + out = fopen(self->windowData.filename, "wt"); + if (out != NULL) { + // Save! + fprintf(out, "%s\n", PROJECT_VERSION); + fprintf(out, "------------------------------------------------------------------------------\n"); + gtk_tree_model_get_iter_first(GTK_TREE_MODEL(self->storeProject), &iter); + do { + if (gtk_tree_model_iter_children(GTK_TREE_MODEL(self->storeProject), &child, &iter)) { + do { + //***TODO*** For RAW we need to store function name somewhere. + gtk_tree_model_get(GTK_TREE_MODEL(self->storeProject), &child, COL_FILENAME, &temp, -1); + fprintf(out, "%s\n", temp); + DEL(temp); + } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(self->storeProject), &child)); + } + } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(self->storeProject), &iter)); + fclose(out); + // We're clean now. + utilSetDirty((WindowDataT *)self, FALSE); + } else { + //***TODO*** Something bad happened. + } + } } EVENT void menuProjectFileSaveAs(GtkWidget *object, gpointer userData) { + (void)object; + if (utilFileSaveAs((WindowDataT *)userData, "*.joe", "Project")) { + menuProjectFileSave(object, (ProjectDataT *)userData); + } } @@ -204,12 +235,71 @@ EVENT void menuProjectFileClose(GtkWidget *object, gpointer userData) { EVENT void menuProjectProjectAdd(GtkWidget *object, gpointer userData) { + ProjectDataT *self = (ProjectDataT *)userData; + GtkWidget *dialog; + GtkFileFilter *filter; + ProjectSectionTypeT section; + char *temp; + (void)object; + + dialog = gtk_file_chooser_dialog_new("Add File to Project", + GTK_WINDOW(self->windowData.window), + GTK_FILE_CHOOSER_ACTION_OPEN, + "_Cancel", GTK_RESPONSE_CANCEL, + "_Open", GTK_RESPONSE_ACCEPT, + NULL + ); + + for (section=0; sectiontreeProject)); + gboolean found = FALSE; + GtkWidget *dialog; + GtkTreeModel *model; + GtkTreeIter iter; + // Is anything selected? + if (gtk_tree_selection_get_selected(selection, &model, &iter)) { + // Are we on a child item? + if (gtk_tree_store_iter_depth(self->storeProject, &iter) > 0) { + found = TRUE; + } + } + + if (found) { + gtk_tree_store_remove(self->storeProject, &iter); + utilSetDirty((WindowDataT *)self, TRUE); + } else { + // Provide help. + dialog = gtk_message_dialog_new(GTK_WINDOW(self->windowData.window), + GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL, + GTK_MESSAGE_INFO, + GTK_BUTTONS_CLOSE, + "Please select a file to remove."); + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + } } @@ -263,7 +353,6 @@ void winProjectCreate(void) { NULL }; GtkWidget **widgets[] = { - NULL, NULL, NULL }; @@ -286,20 +375,17 @@ void winProjectCreate(void) { gtk_tree_view_append_column(GTK_TREE_VIEW(self->treeProject), col); renderer = gtk_cell_renderer_text_new(); gtk_tree_view_column_pack_start(col, renderer, TRUE); - gtk_tree_view_column_add_attribute(col, renderer, "text", 0); + gtk_tree_view_column_add_attribute(col, renderer, "text", COL_FILENAME); self->storeProject = gtk_tree_store_new(1, G_TYPE_STRING); for (i=0; istoreProject, &iter, NULL); - gtk_tree_store_set(self->storeProject, &iter, 0, _SectionName[i], -1); + gtk_tree_store_set(self->storeProject, &iter, COL_FILENAME, _sectionData[i].name, -1); } gtk_tree_view_set_model(GTK_TREE_VIEW(self->treeProject), GTK_TREE_MODEL(self->storeProject)); g_object_unref(self->storeProject); - // Grab title. - self->title = strdup(gtk_window_get_title(GTK_WINDOW(self->windowData.window))); - // Register window & show it. utilWindowRegister(self); gtk_widget_show_all(self->windowData.window); diff --git a/src/utils.c b/src/utils.c index 63b0abf..54bb83a 100644 --- a/src/utils.c +++ b/src/utils.c @@ -111,6 +111,7 @@ gboolean utilFileOpen(WindowDataT *self, char *extension, char *what) { "_Open", GTK_RESPONSE_ACCEPT, NULL ); + filter = gtk_file_filter_new(); gtk_file_filter_set_name(filter, files); gtk_file_filter_add_pattern(filter, extension); @@ -135,6 +136,41 @@ gboolean utilFileOpen(WindowDataT *self, char *extension, char *what) { } +gboolean utilFileSaveAs(WindowDataT *self, char *extension, char *what) { + GtkWidget *dialog; + GtkFileFilter *filter; + gboolean result = FALSE; + char *files = utilCreateString("%s Files", what); + + dialog = gtk_file_chooser_dialog_new("Save As", + GTK_WINDOW(self->window), + GTK_FILE_CHOOSER_ACTION_SAVE, + "_Cancel", GTK_RESPONSE_CANCEL, + "_Save", GTK_RESPONSE_ACCEPT, + NULL); + + gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE); + + filter = gtk_file_filter_new(); + gtk_file_filter_set_name(filter, files); + gtk_file_filter_add_pattern(filter, extension); + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter); + + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { + DEL(self->filename); + self->filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + utilSetDirty(self, TRUE); + result = TRUE; + } + + DEL(files); + + gtk_widget_destroy(dialog); + + return result; +} + + WindowDataT *utilGetWindowData(GtkWidget *window) { return hmget(_windowList, window); } diff --git a/src/vector.c b/src/vector.c index ff0ff64..f782f74 100644 --- a/src/vector.c +++ b/src/vector.c @@ -788,25 +788,12 @@ EVENT void menuVectorFileSave(GtkWidget *object, gpointer userData) { EVENT void menuVectorFileSaveAs(GtkWidget *object, gpointer userData) { - VectorDataT *self = (VectorDataT *)userData; - GtkWidget *dialog; - dialog = gtk_file_chooser_dialog_new("Save As", - GTK_WINDOW(self->windowData.window), - GTK_FILE_CHOOSER_ACTION_SAVE, - "_Cancel", GTK_RESPONSE_CANCEL, - "_Save", GTK_RESPONSE_ACCEPT, - NULL); + (void)object; - gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE); - - if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { - DEL(self->windowData.filename); - self->windowData.filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); - menuVectorFileSave(object, self); + if (utilFileSaveAs((WindowDataT *)userData, "*.vic", "Image")) { + menuVectorFileSave(object, (VectorDataT *)userData); } - - gtk_widget_destroy(dialog); } diff --git a/ui/Project.glade b/ui/Project.glade index 0bcd218..50f2c1f 100644 --- a/ui/Project.glade +++ b/ui/Project.glade @@ -203,6 +203,7 @@ True True False + False 0 True