diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 07e23d36b..073f9c08d 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -590,6 +590,7 @@ public JMenu initDefaultFileMenu() { item.addActionListener(e -> handleOpenPrompt()); defaultFileMenu.add(item); + item = Toolkit.newJMenuItemShift(Language.text("menu.file.sketchbook"), 'K'); item.addActionListener(e -> showSketchbookFrame()); defaultFileMenu.add(item); @@ -598,6 +599,9 @@ public JMenu initDefaultFileMenu() { item.addActionListener(e -> thinkDifferentExamples()); defaultFileMenu.add(item); + item = Toolkit.newJMenuItem(Language.text("menu.file.templates"), 'T'); + defaultFileMenu.add(item); + return defaultFileMenu; } @@ -1095,8 +1099,7 @@ public void modeRemoved(Mode mode) { /** * Create a new untitled document in a new sketch window. */ - public void handleNew() { -// long t1 = System.currentTimeMillis(); + public Editor handleNew() { try { // In 0126, untitled sketches will begin in the temp folder, // and then moved to a new location because Save will default to Save As. @@ -1104,7 +1107,7 @@ public void handleNew() { File newbieDir = SketchName.nextFolder(untitledFolder); // User was told to go outside or other problem happened inside naming. - if (newbieDir == null) return; + if (newbieDir == null) return null; // Make the directory for the new sketch if (!newbieDir.mkdirs()) { @@ -1124,16 +1127,16 @@ public void handleNew() { } String path = newbieFile.getAbsolutePath(); - handleOpenUntitled(path); + return handleOpenUntitled(path); } catch (IOException e) { Messages.showTrace("That's new to me", - "A strange and unexplainable error occurred\n" + - "while trying to create a new sketch.", e, false); + "A strange and unexplainable error occurred\n" + + "while trying to create a new sketch.", e, false); + return null; } } - /** * Prompt for a sketch to open, and open it in a new window. */ @@ -1289,6 +1292,8 @@ private void openContribBundle(String path) { } + + /** * Return true if it's an obvious sketch folder: only .pde files, * and maybe a data folder. Dot files (.DS_Store, ._blah) are ignored. diff --git a/app/src/processing/app/ui/Editor.java b/app/src/processing/app/ui/Editor.java index c3dd0202f..1bbfb7730 100644 --- a/app/src/processing/app/ui/Editor.java +++ b/app/src/processing/app/ui/Editor.java @@ -39,6 +39,7 @@ import java.util.Timer; import java.util.TimerTask; import java.util.stream.Collectors; +import java.nio.file.Files; import javax.swing.*; import javax.swing.border.EmptyBorder; @@ -722,6 +723,12 @@ protected JMenu buildFileMenu(JMenuItem[] exportItems) { item.addActionListener(e -> handleSaveAs()); fileMenu.add(item); + JMenu templatesMenu = new JMenu(Language.text("menu.file.templates")); + Messages.log("templatesMenu"); + loadTemplates(templatesMenu); + fileMenu.add(templatesMenu); + + if (exportItems != null) { for (JMenuItem ei : exportItems) { fileMenu.add(ei); @@ -761,6 +768,105 @@ protected JMenu buildFileMenu(JMenuItem[] exportItems) { } return fileMenu; } + // Load templates from both the repository and the user's Sketchbook folder + private void loadTemplates(JMenu templatesMenu) { + templatesMenu.removeAll(); + List allTemplates = new ArrayList<>(); + + // Load predefined templates from the repository + File repoTemplatesDir = Platform.getContentFile("lib/templates"); + addTemplatesFromDirectory(repoTemplatesDir, allTemplates); + + // Load user-defined templates from the Sketchbook folder + File userTemplatesDir = new File(Base.getSketchbookFolder(), "templates"); + addTemplatesFromDirectory(userTemplatesDir, allTemplates); + + + addTemplatesToMenu(allTemplates, templatesMenu); + } + + private void addTemplatesFromDirectory(File directory, List allTemplates) { + if (directory.exists() && directory.isDirectory()) { + File[] templateFiles = directory.listFiles(); + if (templateFiles != null) { + for (File templateFile : templateFiles) { + allTemplates.add(templateFile); + } + } else { + Messages.log("No template files found in directory: " + directory.getAbsolutePath()); + } + } else { + Messages.log("Directory does not exist or is not a directory: " + directory.getAbsolutePath()); + } + } + + // Add templates to the menu + // Add templates to the menu + private void addTemplatesToMenu(List templates, JMenu templatesMenu) { + templatesMenu.removeAll(); // Clear existing menu items + for (File templateFile : templates) { + String templateName; + if (templateFile.isDirectory()) { + // Handle directory case - might be a sketch folder + templateName = templateFile.getName(); + } else if (templateFile.getName().toLowerCase().endsWith(".pde")) { + templateName = templateFile.getName().replace(".pde", ""); + } else { + templateName = templateFile.getName(); + } + + JMenuItem templateItem = new JMenuItem(templateName); + templateItem.addActionListener(e -> { + try { + String templateCode = ""; + + if (templateFile.isDirectory()) { + // It's a sketch folder, find the main .pde file with the same name as the folder + File mainPdeFile = new File(templateFile, templateFile.getName() + ".pde"); + if (mainPdeFile.exists()) { + templateCode = new String(Files.readAllBytes(mainPdeFile.toPath())); + + } else { + // If main file doesn't exist, try to read any .pde file in the directory + File[] pdeFiles = templateFile.listFiles((dir, name) -> name.toLowerCase().endsWith(".pde")); + if (pdeFiles != null && pdeFiles.length > 0) { + templateCode = new String(Files.readAllBytes(pdeFiles[0].toPath())); + + } + } + } else if (templateFile.getName().toLowerCase().endsWith(".pde")) { + + templateCode = new String(Files.readAllBytes(templateFile.toPath())); + + } else { + templateCode = new String(Files.readAllBytes(templateFile.toPath())); + Messages.log("Unrecognized file type: " + templateFile.getAbsolutePath()); + } + + Editor newEditor = base.handleNew(); + if (newEditor != null) { + + newEditor.insertText(templateCode); + JEditTextArea textArea = newEditor.getTextArea(); + textArea.setCaretPosition(0); + textArea.scrollTo(0, 0); + } else { + Messages.log("Failed to create new editor."); + } + } catch (IOException ex) { + Messages.log("Error reading template file: " + ex.getMessage()); + ex.printStackTrace(); + } catch (Exception ex) { + Messages.log("Unexpected error: " + ex.getMessage()); + ex.printStackTrace(); + } + }); + templatesMenu.add(templateItem); + } + } + + + protected JMenu buildEditMenu() { @@ -2302,7 +2408,9 @@ protected void handleSaveImpl() { statusNotice(Language.text("editor.status.saving")); try { if (sketch.save()) { + statusNotice(Language.text("editor.status.saving.done")); + } else { statusEmpty(); } diff --git a/build/shared/lib/languages/PDE.properties b/build/shared/lib/languages/PDE.properties index 604cf4e41..4e6fe0df6 100644 --- a/build/shared/lib/languages/PDE.properties +++ b/build/shared/lib/languages/PDE.properties @@ -21,6 +21,7 @@ menu.file.recent = Open Recent menu.file.sketchbook = Sketchbook... menu.file.sketchbook.empty = Empty Sketchbook menu.file.examples = Examples... +menu.file.templates=New from Template menu.file.close = Close menu.file.save = Save menu.file.save_as = Save As... diff --git a/build/shared/lib/templates/Animation_Sketch.pde b/build/shared/lib/templates/Animation_Sketch.pde new file mode 100644 index 000000000..62dcabbd3 --- /dev/null +++ b/build/shared/lib/templates/Animation_Sketch.pde @@ -0,0 +1,8 @@ +void setup() { + size(500, 500); + // write code that will be called once in this function +} + +void draw() { + // write code that will be called for every frame here +} \ No newline at end of file diff --git a/build/shared/lib/templates/Fullscreen_Sketch.pde b/build/shared/lib/templates/Fullscreen_Sketch.pde new file mode 100644 index 000000000..1ba74d78f --- /dev/null +++ b/build/shared/lib/templates/Fullscreen_Sketch.pde @@ -0,0 +1,7 @@ +void setup() { + fullScreen(); // create a fullscreen canvas +} + +void draw() { + circle(width / 2, height / 2, height * 0.5); +} \ No newline at end of file diff --git a/build/shared/lib/templates/Interactive_Sketch.pde b/build/shared/lib/templates/Interactive_Sketch.pde new file mode 100644 index 000000000..020a2d6c9 --- /dev/null +++ b/build/shared/lib/templates/Interactive_Sketch.pde @@ -0,0 +1,13 @@ +void setup() { + size(500, 500); + // write code that will be called once in this function +} + +void draw() { + // write code that will be called for every frame here +} + +void mousePressed() { + ellipse(mouseX, mouseY, 20, 20); + // write code that will run when you click +} \ No newline at end of file diff --git a/build/shared/lib/templates/Resizeable_Sketch.pde b/build/shared/lib/templates/Resizeable_Sketch.pde new file mode 100644 index 000000000..e462f604e --- /dev/null +++ b/build/shared/lib/templates/Resizeable_Sketch.pde @@ -0,0 +1,15 @@ +void setup() { + size(500, 500); + windowResizable(true); + // allow the window to be resized +} + +void draw() { + circle(width / 2, height / 2, min(width, height) * 0.5); + // draw a circle that resizes with the window +} + +void windowResized() { + println("Window resized to: " + width + "x" + height); + // this function is called whenever the window is resized +} \ No newline at end of file