diff --git a/examples/C/text-editor/cross_platform_open_file.h b/examples/C/text-editor/cross_platform_open_file.h deleted file mode 100644 index adf21d3d2..000000000 --- a/examples/C/text-editor/cross_platform_open_file.h +++ /dev/null @@ -1,120 +0,0 @@ -#include -#include -#include - -#ifdef _WIN32 - #include - #include -#elif __APPLE__ - #include - #if TARGET_OS_MAC - #include - #include - #endif -#elif __linux__ - #include -#endif - -#define FULL_FILE_BUFFER_SIZE (2 * 1024 * 1024) // 2 MB -char FULL_FILE_BUFFER[FULL_FILE_BUFFER_SIZE]; -char JAVASCRIPT_BUFFER[FULL_FILE_BUFFER_SIZE]; -char FILE_PATH[1024]; - -size_t read_file_into_buffer(const char *filename, char *buffer, size_t buffer_size) { - - FILE *file = fopen(filename, "rb"); - - if (file == NULL) { - fprintf(stderr, "Error: Could not open file %s.\n", filename); - return -1; - } - - size_t bytes_read = fread(buffer, 1, buffer_size, file); - buffer[bytes_read] = '\0'; - - if (ferror(file)) { - fprintf(stderr, "Error: Could not read file %s.\n", filename); - fclose(file); - return -1; - } - - fclose(file); - return bytes_read; -} - -#ifdef _WIN32 - UINT_PTR OpenDialogHooks(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam) { - BringWindowToTop(hdlg); - return 0; - } -#endif - -char* show_file_open_dialog() { - - #ifdef _WIN32 - - OPENFILENAMEA ofn; - ZeroMemory(&ofn, sizeof(OPENFILENAME)); - ofn.lStructSize = sizeof(OPENFILENAME); - ofn.hwndOwner = NULL; - ofn.lpstrFile = FILE_PATH; - ofn.nMaxFile = sizeof(FILE_PATH); - ofn.lpstrFilter = "All Files\0*.*\0"; - ofn.nFilterIndex = 1; - ofn.lpstrFileTitle = NULL; - ofn.nMaxFileTitle = 0; - ofn.lpstrInitialDir = NULL; - ofn.lpfnHook = OpenDialogHooks; - ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; - if (GetOpenFileNameA(&ofn)) { - return FILE_PATH; - } - - #elif __APPLE__ - - @autoreleasepool { - NSOpenPanel *openPanel = [NSOpenPanel openPanel]; - [openPanel setCanChooseFiles:YES]; - [openPanel setCanChooseDirectories:NO]; - [openPanel setAllowsMultipleSelection:NO]; - [openPanel setAllowedFileTypes:nil]; - - if ([openPanel runModal] == NSModalResponseOK) { - NSURL *fileURL = [[openPanel URLs] objectAtIndex:0]; - const char *fileSystemRepresentation = [[fileURL fileSystemRepresentation] UTF8String]; - strncpy(FILE_PATH, fileSystemRepresentation, sizeof(FILE_PATH)); - FILE_PATH[sizeof(FILE_PATH) - 1] = '\0'; - return FILE_PATH; - } - } - - #else - - if (!gtk_init_check(NULL, NULL)) { - fprintf(stderr, "Error: Failed to initialize GTK.\n"); - return NULL; - } - - GtkWidget *dialog = gtk_file_chooser_dialog_new("Open File", NULL, GTK_FILE_CHOOSER_ACTION_OPEN, "_Cancel", GTK_RESPONSE_CANCEL, "_Open", GTK_RESPONSE_ACCEPT, NULL); - GtkFileChooser *chooser = GTK_FILE_CHOOSER(dialog); - gtk_file_chooser_set_select_multiple(chooser, FALSE); - gtk_file_chooser_set_current_folder(chooser, g_get_home_dir()); - - gint response = gtk_dialog_run(GTK_DIALOG(dialog)); - if (response == GTK_RESPONSE_ACCEPT) { - char *filename = gtk_file_chooser_get_filename(chooser); - strncpy(FILE_PATH, filename, sizeof(FILE_PATH)); - FILE_PATH[sizeof(FILE_PATH) - 1] = '\0'; - g_free(filename); - gtk_widget_destroy(dialog); - while (g_main_context_iteration(NULL, FALSE)); - return FILE_PATH; - } - - gtk_widget_destroy(dialog); - while (g_main_context_iteration(NULL, FALSE)); - - #endif - - return NULL; -} diff --git a/examples/C/text-editor/text-editor.c b/examples/C/text-editor/text-editor.c index 77b075c5f..94af4c22e 100644 --- a/examples/C/text-editor/text-editor.c +++ b/examples/C/text-editor/text-editor.c @@ -1,10 +1,6 @@ // Text Editor in C using WebUI #include "webui.h" -#include "cross_platform_open_file.h" - -#include -#include void Close(webui_event_t* e) { printf("Exit.\n"); @@ -13,97 +9,20 @@ void Close(webui_event_t* e) { webui_exit(); } -void Save(webui_event_t* e) { - printf("Save.\n"); - - // Save data received from the UI - FILE *file = fopen(FILE_PATH, "w"); - int results = fputs(e->data, file); - if(results == EOF) { - // Failed to write - } - fclose(file); -} - -void Open(webui_event_t* e) { - printf("Open.\n"); - - // Open a new file - - // Open file and save the path to FILE_PATH - if(show_file_open_dialog() == NULL) - return; - - // Read the full content to FULL_FILE_BUFFER - size_t bytes_read = read_file_into_buffer(FILE_PATH, FULL_FILE_BUFFER, FULL_FILE_BUFFER_SIZE); - if(bytes_read < 1) - return; - - // Send file content - // Encode the full content to base64 - char* file_encoded = webui_encode(FULL_FILE_BUFFER); - if(file_encoded == NULL) - return; - sprintf(JAVASCRIPT_BUFFER, "addText('%s')", file_encoded); - webui_run(e->window, JAVASCRIPT_BUFFER); - - // Send file name - // Encode the file path to base64 - char* path_encoded = webui_encode(FILE_PATH); - if(path_encoded == NULL) - return; - sprintf(JAVASCRIPT_BUFFER, "SetFile('%s')", path_encoded); - webui_run(e->window, JAVASCRIPT_BUFFER); - - // Clean - webui_free(file_encoded); - webui_free(path_encoded); - - /* - // Add line by line example: - - FILE *file = fopen(FILE_PATH, "r"); - if(file == NULL) - return; - - char line[1024] = {0}; - while (fgets(line, 1024, file) != NULL) { - - // Line - char* line_encoded = webui_encode(line); - - if(line_encoded != NULL) { - - char js[1024] = {0}; - - // JS - sprintf(js, "addLine('%s')", line_encoded); - - // Send - webui_run(e->window, js); - - // Clean - webui_free(line_encoded); - } - } - - fclose(file); - */ -} - int main() { - // Create new windows + // Create a new window int MainWindow = webui_new_window(); - // Bind HTML element IDs with a C functions - webui_bind(MainWindow, "Open", Open); - webui_bind(MainWindow, "Save", Save); - webui_bind(MainWindow, "Close", Close); - - // Show a new window + // Set the root folder for the UI webui_set_root_folder(MainWindow, "ui"); - webui_show(MainWindow, "MainWindow.html"); + + // Bind HTML elements with the specified ID to C functions + webui_bind(MainWindow, "close-button", Close); + + // Show the window, preferably in a chromium based browser + if (!webui_show_browser(MainWindow, "MainWindow.html", ChromiumBased)) + webui_show(MainWindow, "MainWindow.html"); // Wait until all windows get closed webui_wait(); diff --git a/examples/C/text-editor/ui/MainWindow.html b/examples/C/text-editor/ui/MainWindow.html index c83695964..c0a209d69 100644 --- a/examples/C/text-editor/ui/MainWindow.html +++ b/examples/C/text-editor/ui/MainWindow.html @@ -2,7 +2,7 @@ - + Text Editor in C using WebUI @@ -10,28 +10,22 @@ - - - - - -
@@ -46,6 +40,12 @@

WebUI Text Editor

webui.me | (C)2023 Hassan Draga

+ + + + + + diff --git a/examples/C/text-editor/ui/js/ui.js b/examples/C/text-editor/ui/js/ui.js index 7847843c8..dbcd74ee5 100644 --- a/examples/C/text-editor/ui/js/ui.js +++ b/examples/C/text-editor/ui/js/ui.js @@ -1,109 +1,119 @@ // Text Editor // Elements -let About = document.getElementById("About"); -let aboutBox = document.getElementById("about-box"); +const aboutBtn = document.getElementById('about-button'); +const aboutBox = document.getElementById('about-box'); +const saveBtn = document.getElementById('save-button'); +const supportsFilePicker = 'showSaveFilePicker' in window; +let fileHandle; +let openFile = { + name: '', + ext: '', +}; // About show -About.onclick = function() { - // Open ABout - aboutBox.style.display = "block"; -} - +aboutBtn.onclick = () => (aboutBox.style.display = 'block'); // About hide -window.onclick = function(event) { - if (event.target == aboutBox) { - // Close About - aboutBox.style.display = "none"; - } -} +aboutBox.onclick = () => (aboutBox.style.display = 'none'); // Create the editor -const editor = document.getElementById("editor"); +const editor = document.getElementById('editor'); const codeMirrorInstance = CodeMirror.fromTextArea(editor, { - mode: "text/x-csrc", + mode: 'text/x-csrc', lineNumbers: true, tabSize: 4, indentUnit: 2, lineWrapping: true, - theme: "lucario" + theme: 'lucario', }); // Change editor language function SetFileModeExtension(extension) { - let mode = ""; + let mode = ''; switch (extension) { - case "js": - mode = "text/javascript"; + case 'js': + mode = 'text/javascript'; break; - case "c": - case "cpp": - case "h": - mode = "text/x-csrc"; + case 'c': + case 'cpp': + case 'h': + mode = 'text/x-csrc'; break; - case "py": - mode = "text/x-python"; + case 'py': + mode = 'text/x-python'; break; - case "html": - mode = "text/html"; + case 'html': + mode = 'text/html'; break; default: - mode = "text/x-csrc"; + mode = 'text/x-csrc'; } - codeMirrorInstance.setOption("mode", mode); -} - -// Add a line to the editor -function addLine(text) { - const lastLine = codeMirrorInstance.lineCount(); - codeMirrorInstance.replaceRange(webui.decode(text) + "\n", {line: lastLine}); - - const element = document.getElementById('SaveLi'); - element.style.color = '#ddecf9'; - element.style.pointerEvents = 'all'; + codeMirrorInstance.setOption('mode', mode); } // Add full text to the editor function addText(text) { - codeMirrorInstance.setValue(webui.decode(text)); + codeMirrorInstance.setValue(text); - const element = document.getElementById('SaveLi'); - element.style.color = '#ddecf9'; - element.style.pointerEvents = 'all'; + saveBtn.style.color = '#ddecf9'; + saveBtn.style.pointerEvents = 'all'; } -// Save the file -function SaveFile() { - const content = codeMirrorInstance.getValue(); - webui.call('Save', content); +function readFile(file) { + const reader = new FileReader(); + reader.onload = (e) => addText(e.target.result); + reader.readAsText(file); } -window.addEventListener("DOMContentLoaded", (event) => { - // Load - codeMirrorInstance.setSize("100%", "99%"); -}); - -function getFileExtension(path) { - console.log('getFileExtension: ' + path); - return path.split('.').pop(); +function setFile(file) { + openFile.name = file.name; + openFile.ext = file.name.split('.').pop(); + // Set file title and language in editor + document.title = file.name; + SetFileModeExtension(openFile.ext); } -function getFileName(path) { - console.log('getFileName: ' + path); - return path.split(/[/\\]/).pop(); +async function OpenFile() { + if (supportsFilePicker) { + [fileHandle] = await showOpenFilePicker({ multiple: false }); + fileData = await fileHandle.getFile(); + readFile(fileData); + setFile(fileData); + } else { + let input = document.createElement('input'); + input.type = 'file'; + input.onchange = (e) => { + readFile(e.target.files[0]); + setFile(e.target.files[0]); + }; + input.click(); + input.remove(); + } } -function changeWindowTitle(newTitle) { - document.title = newTitle; +async function SaveFile() { + const content = codeMirrorInstance.getValue(); + if (supportsFilePicker && fileHandle) { + // Create a FileSystemWritableFileStream to write to + const writableStream = await fileHandle.createWritable(); + await writableStream.write(content); + // Write to disk + await writableStream.close(); + } else { + // Download the file if using filePicker with a fileHandle for saving + // is not supported by the browser. E.g., in Firefox. + const blobData = new Blob([content], { type: 'text/${openFile.ext}' }); + const urlToBlob = window.URL.createObjectURL(blobData); + const a = document.createElement('a'); + a.style.setProperty('display', 'none'); + a.href = urlToBlob; + a.download = document.title; + a.click(); + window.URL.revokeObjectURL(urlToBlob); + a.remove(); + } } -// Set file title and language -function SetFile(path_base64) { - const path = webui.decode(path_base64); - const Extension = getFileExtension(path); - const FileName = getFileName(path); - console.log('Extension: ' + path); - console.log('FileName: ' + path); - SetFileModeExtension(Extension); - changeWindowTitle(FileName); -} +window.addEventListener('DOMContentLoaded', () => { + codeMirrorInstance.setSize('100%', '99%'); +});