Project management is fairly solid, if basic. Now to build a code editor!

This commit is contained in:
Scott Duensing 2023-01-26 19:52:14 -06:00
parent 65d83bd038
commit 2de3ecedad
7 changed files with 156 additions and 39 deletions

View file

@ -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

View file

@ -34,7 +34,7 @@
#endif
#define UTIL_PATH_MAX 1024
extern char __utilFilenameBuffer[FILENAME_MAX];
char *utilCreateString(char *format, ...);

View file

@ -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; i<arrlen(self->targets); i++) {
for (j=0; j<arrlen(self->targets[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; i<self->targets; 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; j<arrlen(t->archs); 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; i<SECTION_COUNT; i++) {
gtk_tree_store_append(store, &iter, NULL);
gtk_tree_store_set(store, &iter, COL_FILENAME, _sectionData[i].name, -1);
}
gtk_tree_view_set_model(GTK_TREE_VIEW(self->treeProject), GTK_TREE_MODEL(store));
g_object_unref(store);
// Select every target and architecture.
for (x=0; x<arrlen(self->targets); x++) {
for (y=0; y<arrlen(self->targets[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; section<SECTION_COUNT; section++) {
if (_sectionData[section].extension != NULL) {
filter = gtk_file_filter_new();
@ -431,9 +489,18 @@ EVENT void menuProjectProjectAdd(GtkWidget *object, gpointer userData) {
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
}
}
filter = gtk_file_filter_new();
gtk_file_filter_set_name(filter, _sectionData[SECTION_RAW_DATA].name);
gtk_file_filter_add_pattern(filter, "*");
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
temp = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
if (path != NULL) {
cwk_path_get_relative(path,temp, __utilFilenameBuffer, sizeof(__utilFilenameBuffer));
DEL(temp);
temp = strdup(__utilFilenameBuffer);
}
addToTree(self, temp);
utilSetDirty((WindowDataT *)self, TRUE);
DEL(temp);
@ -692,6 +759,26 @@ static void saveConfig(ProjectDataT *self) {
}
EVENT void treeProjectRowActivated(GtkTreeView *treeView, GtkTreePath *path, GtkTreeViewColumn *column, gpointer userData) {
ProjectDataT *self = (ProjectDataT *)userData;
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(self->treeProject));
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);
}

View file

@ -21,7 +21,9 @@
#include <sys/stat.h>
#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) {

BIN
thirdparty/cwalk-master.zip vendored Normal file

Binary file not shown.

View file

@ -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/.

View file

@ -35,6 +35,7 @@
<property name="label" translatable="yes">New</property>
<property name="use-underline">True</property>
<signal name="activate" handler="menuProjectFileNew" swapped="no"/>
<accelerator key="n" signal="activate" modifiers="GDK_CONTROL_MASK"/>
</object>
</child>
<child>
@ -44,6 +45,7 @@
<property name="label" translatable="yes">Open...</property>
<property name="use-underline">True</property>
<signal name="activate" handler="menuProjectFileOpen" swapped="no"/>
<accelerator key="o" signal="activate" modifiers="GDK_CONTROL_MASK"/>
</object>
</child>
<child>
@ -53,6 +55,7 @@
<property name="label" translatable="yes">Save</property>
<property name="use-underline">True</property>
<signal name="activate" handler="menuProjectFileSave" swapped="no"/>
<accelerator key="s" signal="activate" modifiers="GDK_CONTROL_MASK"/>
</object>
</child>
<child>
@ -62,6 +65,7 @@
<property name="label" translatable="yes">Save As...</property>
<property name="use-underline">True</property>
<signal name="activate" handler="menuProjectFileSaveAs" swapped="no"/>
<accelerator key="s" signal="activate" modifiers="GDK_SHIFT_MASK | GDK_CONTROL_MASK"/>
</object>
</child>
<child>
@ -100,6 +104,7 @@
<property name="label" translatable="yes">Add File...</property>
<property name="use-underline">True</property>
<signal name="activate" handler="menuProjectProjectAdd" swapped="no"/>
<accelerator key="Insert" signal="activate"/>
</object>
</child>
<child>
@ -109,6 +114,7 @@
<property name="label" translatable="yes">Remove File</property>
<property name="use-underline">True</property>
<signal name="activate" handler="menuProjectProjectRemove" swapped="no"/>
<accelerator key="Delete" signal="activate"/>
</object>
</child>
</object>
@ -156,6 +162,7 @@
<property name="label" translatable="yes">Build Project</property>
<property name="use-underline">True</property>
<signal name="activate" handler="menuProjectBuildBuild" swapped="no"/>
<accelerator key="b" signal="activate" modifiers="GDK_CONTROL_MASK"/>
</object>
</child>
</object>
@ -179,6 +186,7 @@
<property name="label" translatable="yes">Project Editor...</property>
<property name="use-underline">True</property>
<signal name="activate" handler="menuProjectHelpProject" swapped="no"/>
<accelerator key="F1" signal="activate"/>
</object>
</child>
</object>
@ -200,6 +208,7 @@
<property name="enable-search">False</property>
<property name="search-column">0</property>
<property name="enable-tree-lines">True</property>
<signal name="row-activated" handler="treeProjectRowActivated" swapped="no"/>
<child internal-child="selection">
<object class="GtkTreeSelection"/>
</child>