diff --git a/CMakeLists.txt b/CMakeLists.txt index 5886eb0..c45cd79 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,6 +38,7 @@ set(CMAKE_C_STANDARD 99) set(SOURCE_FILES thirdparty-installed/memwatch/memwatch.c + thirdparty-installed/cwalk-master/src/cwalk.c ui/generated/resources.c src/main.c src/utils.c @@ -63,6 +64,7 @@ add_custom_target(GENERATE_UI_HEADERS COMMAND ${CMAKE_SOURCE_DIR}/tools/prebuild.sh "${CMAKE_SOURCE_DIR}" BYPRODUCTS ${CMAKE_SOURCE_DIR}/thirdparty-installed/memwatch/memwatch.c + ${CMAKE_SOURCE_DIR}/thirdparty-installed/cwalk-master/src/cwalk.c ${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/scintilla.a ${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/liblexilla.a ${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/libgpg-error.a diff --git a/include/utils.h b/include/utils.h index 62cf18b..b709f53 100644 --- a/include/utils.h +++ b/include/utils.h @@ -34,7 +34,7 @@ #endif -#define UTIL_PATH_MAX 1024 +extern char __utilFilenameBuffer[FILENAME_MAX]; char *utilCreateString(char *format, ...); diff --git a/src/project.c b/src/project.c index 3952f52..7fd68e6 100644 --- a/src/project.c +++ b/src/project.c @@ -26,6 +26,7 @@ #include "common.h" #include "project.h" +#include "cwalk.h" #include "utils.h" #include "http.h" #include "ssh.h" @@ -89,7 +90,7 @@ static SectionDataT _sectionData[] = { { "Vector", "*.vic" }, { "Sound", "*.snd" }, { "Music", "*.mod" }, - { "Raw Data", "*.raw" }, + { "Raw Data", NULL }, { "Cooked Data", NULL }, { NULL, NULL } }; @@ -116,6 +117,7 @@ EVENT void menuProjectHelpProject(GtkWidget *object, gpointer userData) static void saveConfig(ProjectDataT *self); static TargetT **targetArrayCopy(TargetT **targets); static void targetArrayDelete(TargetT ***array); +EVENT void treeProjectRowActivated(GtkTreeView *treeView, GtkTreePath *path, GtkTreeViewColumn *column, gpointer userData); static gboolean updateBuildOptions(ProjectDataT *self); EVENT gboolean winProjectClose(GtkWidget *object, gpointer userData); static void winProjectDelete(gpointer userData); @@ -123,15 +125,31 @@ static void winProjectDelete(gpointer userData); static void addToTree(ProjectDataT *self, char *filename) { ProjectSectionTypeT section; - char temp[4]; - GtkTreeIter iterParent; + char *temp = NULL; GtkTreeIter iter; + GtkTreeIter child; GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(self->treeProject)); + ProjectSectionTypeT foundAt = SECTION_RAW_DATA; // If it isn't a file we know, put it in "Raw Data". int fileLen; int extLen; // Is it long enough? if (strlen(filename) > 2) { + // Is this already in the tree? This is a pretty brain-dead test. + gtk_tree_model_get_iter_first(model, &iter); + do { + if (gtk_tree_model_iter_children(model, &child, &iter)) { + do { + gtk_tree_model_get(model, &child, COL_FILENAME, &temp, -1); + if (strcmp(temp, filename) == 0) { + DEL(temp); // This generates an unknown pointer warning in memwatch. Pretty sure it's bogus. + return; // Silently fail to add on name collision. + } + DEL(temp); // This generates an unknown pointer warning in memwatch. Pretty sure it's bogus. + } while (gtk_tree_model_iter_next(model, &child)); + } + } while (gtk_tree_model_iter_next(model, &iter)); + // Find proper section. for (section = 0; section < SECTION_COUNT; section++) { if (_sectionData[section].extension != NULL) { @@ -139,15 +157,23 @@ static void addToTree(ProjectDataT *self, char *filename) { 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(model, &iterParent, temp); - gtk_tree_store_append(GTK_TREE_STORE(model), &iter, &iterParent); - gtk_tree_store_set(GTK_TREE_STORE(model), &iter, COL_FILENAME, filename, -1); - //***TODO*** Need to store extra RAW data somewhere. + foundAt = section; break; } } } + DEL(temp); + fileLen = 0; + utilEnsureBufferSize(&temp, &fileLen, 4); // fileLen is just a throwaway here. + snprintf(temp, 4, "%d", foundAt); + gtk_tree_model_get_iter_from_string(model, &iter, temp); + gtk_tree_store_append(GTK_TREE_STORE(model), &child, &iter); + gtk_tree_store_set(GTK_TREE_STORE(model), &child, COL_FILENAME, filename, -1); + DEL(temp); + + //***TODO*** Need to store extra RAW data somewhere. + + gtk_tree_view_expand_all(GTK_TREE_VIEW(self->treeProject)); } } @@ -233,12 +259,23 @@ static void loadProject(ProjectDataT *self) { size_t len = 0; char *c = NULL; TargetT *t = NULL; - ArchT *a = NULL; int i; int j; + char *path = NULL; in = fopen(self->windowData.filename, "rt"); if (in != NULL) { + // Set all our known archs to FALSE. + for (i=0; itargets); i++) { + for (j=0; jtargets[i]->archs); j++) { + self->targets[i]->archs[j]->selected = FALSE; + } + } + // Find path of config file. + path = strdup(self->windowData.filename); + cwk_path_get_dirname(path, &i); + if (i > 0) path[i] = 0; + // Load config. utilEnsureBufferSize(&line, &len, 1024); // Not technically needed, but fixes a pointer warning from memmaker. while (getline(&line, &len, in) != -1) { if (strlen(line) > 0) line[strlen(line) - 1] = 0; @@ -248,7 +285,12 @@ static void loadProject(ProjectDataT *self) { if (strcasecmp(c, "source") == 0) { c = utilGetToken(NULL, " ", "\"", "\""); utilDequote(c); - addToTree(self, c); + cwk_path_get_relative(path, c, __utilFilenameBuffer, sizeof(__utilFilenameBuffer)); + if (__utilFilenameBuffer[0] == 0) { + addToTree(self, c); + } else { + addToTree(self, __utilFilenameBuffer); + } } // Is this a 'target' line? if (strcasecmp(c, "target") == 0) { @@ -258,11 +300,7 @@ static void loadProject(ProjectDataT *self) { for (i=0; itargets; i++) { if (strcasecmp(self->targets[i]->name, c) == 0) { t = self->targets[i]; - // We know this target. Set all our known archs to FALSE. - for (j=0; jarchs); j++) { - t->archs[j]->selected = FALSE; - } - // Iterate over specified arches and turn them on if known. + // We know this target. Iterate over specified arches and turn them on if known. while (c != NULL) { c = utilGetToken(NULL, " ", "\"", "\""); if (c != NULL) { @@ -282,7 +320,7 @@ static void loadProject(ProjectDataT *self) { } fclose(in); DEL(line); - gtk_tree_view_expand_all(GTK_TREE_VIEW(self->treeProject)); + DEL(path); utilSetDirty((WindowDataT *)self, FALSE); // Do again - loading text marks us dirty. } else { //***TODO*** Something bad happened. @@ -295,20 +333,31 @@ EVENT void menuProjectFileNew(GtkWidget *object, gpointer userData) { GtkTreeIter iter; ProjectSectionTypeT i; GtkTreeStore *store; + int x; + int y; (void)object; + // Reset project tree. gtk_tree_view_set_model(GTK_TREE_VIEW(self->treeProject), NULL); - store = gtk_tree_store_new(1, G_TYPE_STRING); - for (i=0; itreeProject), GTK_TREE_MODEL(store)); g_object_unref(store); + + // Select every target and architecture. + for (x=0; xtargets); x++) { + for (y=0; ytargets[x]->archs); y++) { + self->targets[x]->archs[y]->selected = TRUE; + } + } + + // Nuke filename & mark clean. + DEL(self->windowData.filename); + utilSetDirty(&self->windowData, FALSE); } @@ -411,7 +460,9 @@ EVENT void menuProjectProjectAdd(GtkWidget *object, gpointer userData) { GtkWidget *dialog; GtkFileFilter *filter; ProjectSectionTypeT section; - char *temp; + char *temp = NULL; + char *path = NULL; + int x; (void)object; @@ -423,6 +474,13 @@ EVENT void menuProjectProjectAdd(GtkWidget *object, gpointer userData) { NULL ); + if (self->windowData.filename != NULL) { + path = strdup(self->windowData.filename); + cwk_path_get_dirname(path, &x); + if (x > 0) path[x] = 0; + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),path); + } + for (section=0; sectiontreeProject)); + GtkTreeIter iter; + char *name = NULL; + char *pathString = NULL; + + pathString = gtk_tree_path_to_string(path); + if (strstr(pathString, ":") != NULL) { + gtk_tree_model_get_iter_from_string(model, &iter, pathString); + gtk_tree_model_get(model, &iter, COL_FILENAME, &name, -1); + + debug("Double click! [%s] [%s]\n", pathString, name); + + DEL(name); + } + DEL(pathString); +} + + static gboolean updateBuildOptions(ProjectDataT *self) { char *test = NULL; char *name = NULL; @@ -883,6 +970,9 @@ void winProjectCreate(void) { widgets[1] = &self->treeProject; utilGetWidgetsFromMemory("/com/kangaroopunch/joeydev/Project.glade", widgetNames, widgets, self); + // Register window. + utilWindowRegister(self); + // Build tree. col = gtk_tree_view_column_new(); gtk_tree_view_append_column(GTK_TREE_VIEW(self->treeProject), col); @@ -896,15 +986,14 @@ void winProjectCreate(void) { // Load server settings. loadConfig(self); - // Register window & show it. - utilWindowRegister(self); + // Show window. gtk_widget_show_all(self->windowData.window); // Attempt to load build settings from build server. updateBuildOptions(self); //***DEBUG*** - self->windowData.filename = strdup("/home/scott/code/joeydev/cmake-build-debug/test.joe"); + self->windowData.filename = strdup("/home/scott/joeyapps/warehouse/Warehouse.joe"); loadProject(self); } diff --git a/src/utils.c b/src/utils.c index 70c75b9..581d71c 100644 --- a/src/utils.c +++ b/src/utils.c @@ -21,7 +21,9 @@ #include + #include "utils.h" +#include "cwalk.h" #ifdef _WIN32 @@ -39,6 +41,8 @@ typedef struct WindowListS { static WindowListT *_windowList = NULL; +char __utilFilenameBuffer[FILENAME_MAX]; + char *utilCreateString(char *format, ...) { va_list args; @@ -190,6 +194,7 @@ gboolean utilFileSaveAs(WindowDataT *self, char *extension, char *what) { GtkFileFilter *filter; gboolean result = FALSE; char *files = utilCreateString("%s Files", what); + int x; dialog = gtk_file_chooser_dialog_new("Save As", GTK_WINDOW(self->window), @@ -198,6 +203,13 @@ gboolean utilFileSaveAs(WindowDataT *self, char *extension, char *what) { "_Save", GTK_RESPONSE_ACCEPT, NULL); + if (self->filename != NULL) { + memcpy(__utilFilenameBuffer, self->filename, strlen(self->filename) + 1); + cwk_path_get_dirname(__utilFilenameBuffer, &x); + if (x > 0) __utilFilenameBuffer[x] = 0; + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),__utilFilenameBuffer); + } + gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE); filter = gtk_file_filter_new(); @@ -295,38 +307,37 @@ gboolean utilGetWidgetsFromMemory(char *resource, char *name[], GtkWidget **widg gboolean utilMkDirP(const char *dir, const mode_t mode) { - char tmp[UTIL_PATH_MAX]; char *p = NULL; struct stat sb; size_t len; // Make copy of dir. - len = strnlen(dir, UTIL_PATH_MAX); - if (len == 0 || len == UTIL_PATH_MAX) { + len = strnlen(dir, FILENAME_MAX); + if (len == 0 || len == FILENAME_MAX) { return -1; } - memcpy(tmp, dir, len); - tmp[len] = '\0'; + memcpy(__utilFilenameBuffer, dir, len); + __utilFilenameBuffer[len] = '\0'; // Remove trailing slash. - if (tmp[len - 1] == UTIL_PATH_CHAR) { - tmp[len - 1] = '\0'; + if (__utilFilenameBuffer[len - 1] == UTIL_PATH_CHAR) { + __utilFilenameBuffer[len - 1] = '\0'; } // Does it already exist? - if (stat(tmp, &sb) == 0) { + if (stat(__utilFilenameBuffer, &sb) == 0) { if (S_ISDIR(sb.st_mode)) { return TRUE; } } // Recursive mkdir. - for (p = tmp + 1; *p; p++) { + for (p = __utilFilenameBuffer + 1; *p; p++) { if (*p == UTIL_PATH_CHAR) { *p = 0; - if (stat(tmp, &sb) != 0) { + if (stat(__utilFilenameBuffer, &sb) != 0) { // Does not exist - create it. - if (ourMkdir(tmp, mode) < 0) { + if (ourMkdir(__utilFilenameBuffer, mode) < 0) { return FALSE; } } else { @@ -339,9 +350,9 @@ gboolean utilMkDirP(const char *dir, const mode_t mode) { } } // Check path - if (stat(tmp, &sb) != 0) { + if (stat(__utilFilenameBuffer, &sb) != 0) { // Does not exist - create it. - if (ourMkdir(tmp, mode) < 0) { + if (ourMkdir(__utilFilenameBuffer, mode) < 0) { return FALSE; } } else { @@ -408,9 +419,9 @@ void utilSetDirty(WindowDataT *self, gboolean dirty) { self->isDirty = dirty; if (dirty) { if (self->filename) { - title = utilCreateString("%s - %s *", self->title, self->filename); + title = utilCreateString("%s - * %s", self->title, self->filename); } else { - title = utilCreateString("%s - (no name) *", self->title); + title = utilCreateString("%s - * (no name)", self->title); } } else { if (self->filename) { diff --git a/thirdparty/cwalk-master.zip b/thirdparty/cwalk-master.zip new file mode 100644 index 0000000..4a1943b Binary files /dev/null and b/thirdparty/cwalk-master.zip differ diff --git a/tools/prebuild.sh b/tools/prebuild.sh index fb4e8ac..36b4d0c 100755 --- a/tools/prebuild.sh +++ b/tools/prebuild.sh @@ -39,6 +39,12 @@ pushd "${ROOT}" || exit &> /dev/null cp -f ${INSTALLED}/memwatch/memwatch.h ${INSTALLED}/include/. fi + if [[ ! -f ${INSTALLED}/cwalk-master/src/cwalk.c ]]; then + echo Unpacking Dependency: cwalk... + unzip ${THIRDPARTY}/cwalk-master.zip + cp -f ${INSTALLED}/cwalk-master/include/cwalk.h ${INSTALLED}/include/. + fi + if [[ ! -f ${INSTALLED}/include/stb_ds.h ]]; then echo Installing Dependency: stb_ds... cp -f ${THIRDPARTY}/stb_ds.h ${INSTALLED}/include/. diff --git a/ui/Project.glade b/ui/Project.glade index d24ea7d..65ef1bb 100644 --- a/ui/Project.glade +++ b/ui/Project.glade @@ -35,6 +35,7 @@ New True + @@ -44,6 +45,7 @@ Open... True + @@ -53,6 +55,7 @@ Save True + @@ -62,6 +65,7 @@ Save As... True + @@ -100,6 +104,7 @@ Add File... True + @@ -109,6 +114,7 @@ Remove File True + @@ -156,6 +162,7 @@ Build Project True + @@ -179,6 +186,7 @@ Project Editor... True + @@ -200,6 +208,7 @@ False 0 True +