From 0064ac3b00ed62c757354827487f2c1a7beefd03 Mon Sep 17 00:00:00 2001 From: INNOCENT-ops806 <240418541@tut4life.ac.za> Date: Wed, 6 Aug 2025 07:14:18 +0200 Subject: [PATCH 01/48] fix: corrected a spelling error in the readme file The word was previously mispelled as 'araound' --- README.md | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 45a4777..314a638 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,3 @@ - .*?", readme_content, re.DOTALL) + assert len(table_rows) >= 1, "Should have at least one table row" + + # Test for proper cell structure + table_cells = re.findall(r"", readme_content, re.DOTALL) + assert len(table_cells) >= 2, "Should have at least two table cells" + + def test_app_icon_reference(self, readme_content): + """Test that app icon image reference is properly formatted.""" + img_pattern = r'' + img_matches = re.findall(img_pattern, readme_content) + + assert len(img_matches) > 0, "Should contain at least one img tag" + + for src, width in img_matches: + assert src.startswith("./"), "Image source should use relative path" + assert "appicon.png" in src, "Should reference the app icon file" + assert width.endswith("%"), "Width should be specified as percentage" + + def test_github_actions_badge(self, readme_content): + """Test that GitHub Actions CI badge is present and properly formatted.""" + badge_pattern = r'\[![^]]+\]\([^)]+\)' + badges = re.findall(badge_pattern, readme_content) + + assert len(badges) > 0, "Should contain at least one badge" + assert "Java CI with Maven" in readme_content, "Should contain Java CI badge text" + assert "actions/workflows/maven.yml" in readme_content, "Should reference Maven workflow" + + def test_required_sections_present(self, readme_content): + """Test that all required sections are present in the README.""" + required_sections = [ + "## About", + "## Download", + "## Building", + "## Inspired by", + "## References", + "## License" + ] + + for section in required_sections: + assert section in readme_content, f"Required section '{section}' should be present" + + def test_build_instructions_valid(self, readme_content): + """Test that build instructions are present and properly formatted.""" + # Test for git clone command + assert "git clone" in readme_content, "Should contain git clone command" + assert "github.com" in readme_content, "Should reference GitHub repository" + + # Test for Maven build command + assert "mvn package" in readme_content, "Should contain Maven package command" + + # Test for Java execution command + assert "java -jar" in readme_content, "Should contain Java execution command" + assert "target/" in readme_content, "Should reference target directory" + assert ".jar" in readme_content, "Should reference JAR file" + + def test_code_blocks_properly_formatted(self, readme_content): + """Test that code blocks are properly formatted with language specifiers.""" + code_block_pattern = r'```(\w+)?\n(.*?)\n```' + code_blocks = re.findall(code_block_pattern, readme_content, re.DOTALL) + + assert len(code_blocks) >= 2, "Should contain at least 2 code blocks" + + # Check for shell/bash code blocks + shell_blocks = [content for lang, content in code_blocks if lang in ['sh', 'bash', 'shell']] + assert len(shell_blocks) >= 1, "Should contain at least one shell code block" + + def test_external_references_format(self, readme_content): + """Test that external references are properly formatted.""" + # Test for OpenSCAD reference + assert "OpenSCAD" in readme_content, "Should reference OpenSCAD" + assert "openscad.org" in readme_content, "Should contain OpenSCAD URL" + + # Test for java image filters reference + assert "jhlabs.com" in readme_content, "Should reference JH Labs filters" + + # Test for Icons8 reference + assert "icons8.com" in readme_content, "Should reference Icons8" + + @pytest.mark.parametrize("url", [ + "https://github.com/Glimmr-Lang/PicassoCode/actions/workflows/maven.yml", + "https://openscad.org/", + "http://www.jhlabs.com/ip/filters/index.html", + "https://icons8.com/icons/parakeet--style-parakeet" + ]) + def test_external_urls_accessible(self, url): + """Test that external URLs mentioned in README are accessible (mocked for testing).""" + with patch('requests.get') as mock_get: + mock_response = Mock() + mock_response.status_code = 200 + mock_response.raise_for_status.return_value = None + mock_get.return_value = mock_response + + response = requests.get(url, timeout=10) + assert response.status_code == 200, f"URL {url} should be accessible" + mock_get.assert_called_once_with(url, timeout=10) + + def test_license_section_format(self, readme_content): + """Test that license section contains proper ASCII art and license info.""" + license_section = readme_content[readme_content.find("## License"):] + + # Test for ASCII art presence + assert "drawString" in license_section, "License section should contain drawString function" + assert "Creativity + Logic + Math" in license_section, "Should contain project motto" + assert "MIT LICENSE" in license_section, "Should mention MIT license" + + # Test for proper code block formatting in license + assert '```sh' in license_section, "License code should be in shell code block" + + def test_tagline_consistency(self, readme_content): + """Test that the project tagline appears consistently throughout.""" + tagline = "Creativity + Logic + Math" + tagline_occurrences = readme_content.count(tagline) + assert tagline_occurrences >= 2, f"Tagline '{tagline}' should appear at least twice" + + def test_spelling_and_consistency(self, readme_content): + """Test for potential spelling inconsistencies in project name.""" + # The README has both "Piccaso" and "Piccasso" - test that both variants are intentional + piccaso_count = readme_content.count("Piccaso") + piccasso_count = readme_content.count("Piccasso") + + assert piccaso_count > 0, "Should contain 'Piccaso' variant" + assert piccasso_count > 0, "Should contain 'Piccasso' variant" + + # Warn about inconsistency (this is more of a documentation test) + total_variants = piccaso_count + piccasso_count + assert total_variants >= 2, "Project name should appear multiple times" + + def test_markdown_syntax_validity(self, readme_content): + """Test basic markdown syntax validity.""" + lines = readme_content.split('\n') + + # Test for proper heading syntax + heading_lines = [line for line in lines if line.startswith('#')] + for heading in heading_lines: + assert re.match(r'^#{1,6}\s+\S+', heading), f"Invalid heading format: {heading}" + + # Test for balanced HTML tags in the content + html_tags = re.findall(r'<(\/?[^>]+)>', readme_content) + opening_tags = [tag for tag in html_tags if not tag.startswith('/')] + closing_tags = [tag[1:] for tag in html_tags if tag.startswith('/')] + + # Basic balance check for common tags + for tag in ['table', 'tr', 'td', 'h3', 'h6', 'p', 'img']: + opening_count = sum(1 for t in opening_tags if t.split()[0] == tag) + closing_count = closing_tags.count(tag) + if tag != 'img': # img is self-closing + assert opening_count == closing_count, f"Unbalanced {tag} tags" + + def test_repository_references_consistency(self, readme_content): + """Test that repository references are consistent.""" + # Extract repository URLs + repo_urls = re.findall(r'github\.com[:/][^/\s)]+/[^/\s)]+', readme_content) + + assert len(repo_urls) > 0, "Should contain GitHub repository references" + + # Check for consistency in repository naming + unique_repos = set(repo_urls) + # There might be slight variations (Glimmr-Lang/PicassoCode vs hexaredecimal/Piccode) + # This test documents the current state + assert len(unique_repos) >= 1, "Should reference at least one repository" + + def test_download_section_placeholder(self, readme_content): + """Test that download section has appropriate placeholder text.""" + download_section_match = re.search(r'## Download.*?## Building', readme_content, re.DOTALL) + assert download_section_match, "Should have Download section before Building section" + + download_content = download_section_match.group(0) + assert "Coming soon" in download_content, "Download section should indicate coming soon" + + def test_file_encoding_and_format(self): + """Test that README file has proper encoding and line endings.""" + readme_path = Path("README.md") + if readme_path.exists(): + # Test that file can be read as UTF-8 + try: + content = readme_path.read_text(encoding='utf-8') + assert len(content) > 0, "File should be readable as UTF-8" + except UnicodeDecodeError: + pytest.fail("README.md should be encoded in UTF-8") + + # Test for reasonable line lengths (soft limit) + lines = content.split('\n') + long_lines = [i for i, line in enumerate(lines, 1) if len(line) > 120] + # This is a soft warning rather than hard failure + if len(long_lines) > 3: + pytest.warn(f"Many lines exceed 120 characters: lines {long_lines[:5]}") + + +class TestReadmeContentQuality: + """Additional tests for README content quality and completeness.""" + + @pytest.fixture + def readme_content(self): + """Fixture to load README.md content for testing.""" + readme_path = Path("README.md") + if readme_path.exists(): + return readme_path.read_text(encoding='utf-8') + return "" + + def test_inspiration_section_completeness(self, readme_content): + """Test that inspiration section provides adequate context.""" + inspiration_match = re.search(r'## Inspired by.*?## References', readme_content, re.DOTALL) + assert inspiration_match, "Should have complete Inspired by section" + + inspiration_content = inspiration_match.group(0) + assert len(inspiration_content.strip()) > 200, "Inspiration section should be substantial" + assert "OpenSCAD" in inspiration_content, "Should reference OpenSCAD as inspiration" + assert "2D" in inspiration_content, "Should mention 2D aspect" + + def test_build_command_completeness(self, readme_content): + """Test that build commands are complete and executable.""" + # Extract all shell commands + shell_commands = re.findall(r'```sh\n(.*?)\n```', readme_content, re.DOTALL) + + build_commands = [] + for command_block in shell_commands: + commands = command_block.strip().split('\n') + build_commands.extend([cmd.strip() for cmd in commands if cmd.strip()]) + + # Should have git clone, cd, and mvn commands + git_commands = [cmd for cmd in build_commands if cmd.startswith('git')] + cd_commands = [cmd for cmd in build_commands if cmd.startswith('cd')] + mvn_commands = [cmd for cmd in build_commands if cmd.startswith('mvn')] + java_commands = [cmd for cmd in build_commands if cmd.startswith('java')] + + assert len(git_commands) >= 1, "Should have git clone command" + assert len(cd_commands) >= 1, "Should have cd command" + assert len(mvn_commands) >= 1, "Should have mvn command" + assert len(java_commands) >= 1, "Should have java execution command" + + def test_visual_elements_present(self, readme_content): + """Test that visual elements enhance the README presentation.""" + # Should have app icon + assert 'src="./src/main/resources/applogo/appicon.png"' in readme_content, "Should reference app icon" + + # Should have CI badge + assert "badge.svg" in readme_content, "Should have CI status badge" + + # Should have ASCII art in license + ascii_art_indicators = ["▄▖▘", "▙▌▌▛", "▌ ▌▙"] + ascii_present = any(indicator in readme_content for indicator in ascii_art_indicators) + assert ascii_present, "Should contain ASCII art in license section" + + def test_thank_you_message(self, readme_content): + """Test that README ends with appropriate thank you message.""" + assert "Thank you for viewing" in readme_content, "Should end with thank you message" + + def test_repository_url_consistency(self, readme_content): + """Test consistency between different repository URLs mentioned.""" + # Extract git clone URL + git_clone_match = re.search(r'git clone (git@github\.com:[^/]+/[^\s]+)', readme_content) + if git_clone_match: + git_url = git_clone_match.group(1) + # Should be consistent naming + assert "Piccode" in git_url, "Git clone URL should reference Piccode repository" + + # Extract badge URL + badge_match = re.search(r'github\.com/([^/]+/[^/]+)/actions', readme_content) + if badge_match: + badge_repo = badge_match.group(1) + assert "/" in badge_repo, "Badge should reference valid GitHub repo format" + + def test_section_ordering(self, readme_content): + """Test that sections appear in logical order.""" + sections = ["## About", "## Download", "## Building", "## Inspired by", "## References", "## License"] + + section_positions = {} + for section in sections: + pos = readme_content.find(section) + if pos != -1: + section_positions[section] = pos + + # Verify sections appear in expected order + ordered_sections = sorted(section_positions.items(), key=lambda x: x[1]) + expected_order = ["## About", "## Download", "## Building", "## Inspired by", "## References", "## License"] + + actual_order = [section for section, _ in ordered_sections] + for i, expected in enumerate(expected_order): + if i < len(actual_order): + assert actual_order[i] == expected, f"Section {expected} should appear before later sections" + + +class TestReadmeEdgeCases: + """Test edge cases and potential issues in README content.""" + + @pytest.fixture + def readme_content(self): + """Fixture to load README.md content for testing.""" + readme_path = Path("README.md") + if readme_path.exists(): + return readme_path.read_text(encoding='utf-8') + return "" + + def test_no_broken_markdown_links(self, readme_content): + """Test that markdown links are properly formatted.""" + # Find all markdown links + link_pattern = r'\[([^\]]+)\]\(([^)]+)\)' + links = re.findall(link_pattern, readme_content) + + for link_text, link_url in links: + assert link_text.strip(), "Link text should not be empty" + assert link_url.strip(), "Link URL should not be empty" + assert not link_url.startswith(' '), "Link URL should not start with space" + assert not link_url.endswith(' '), "Link URL should not end with space" + + def test_html_img_attributes(self, readme_content): + """Test that HTML img tags have required attributes.""" + img_tags = re.findall(r']+>', readme_content) + + for img_tag in img_tags: + assert 'src=' in img_tag, f"IMG tag should have src attribute: {img_tag}" + # Width is optional but should be properly formatted if present + if 'width=' in img_tag: + width_match = re.search(r'width="([^"]+)"', img_tag) + if width_match: + width_value = width_match.group(1) + # Should be percentage or pixel value + assert width_value.endswith('%') or width_value.endswith('px') or width_value.isdigit(), \ + f"Width value should be valid CSS unit: {width_value}" + + def test_code_block_completeness(self, readme_content): + """Test that code blocks are complete and not malformed.""" + # Count opening and closing code block markers + opening_blocks = readme_content.count('```') + assert opening_blocks % 2 == 0, "Code blocks should have matching opening and closing markers" + + # Test that code blocks have content + code_block_pattern = r'```[^\n]*\n(.*?)\n```' + code_blocks = re.findall(code_block_pattern, readme_content, re.DOTALL) + + for block_content in code_blocks: + assert block_content.strip(), "Code blocks should not be empty" + + def test_ascii_art_integrity(self, readme_content): + """Test that ASCII art in license section is properly formatted.""" + license_section = readme_content[readme_content.find("## License"):] + + if "drawString" in license_section: + # Extract the ASCII art + art_match = re.search(r'drawString\("([^"]+)"', license_section, re.DOTALL) + if art_match: + ascii_art = art_match.group(1) + lines = ascii_art.split('\\n') + + # Should have box-drawing characters + box_chars_present = any(char in ascii_art for char in ['▄', '▖', '▘', '▌', '▙', '█']) + assert box_chars_present, "ASCII art should contain Unicode box-drawing characters" + + # Should have consistent line structure for the box + border_lines = [line for line in lines if '+' in line and '-' in line] + assert len(border_lines) >= 2, "ASCII art should have top and bottom borders" + + def test_whitespace_consistency(self, readme_content): + """Test for consistent whitespace usage.""" + lines = readme_content.split('\n') + + # Check for trailing whitespace (common markdown issue) + trailing_whitespace_lines = [i+1 for i, line in enumerate(lines) if line.rstrip() != line] + assert len(trailing_whitespace_lines) < 5, \ + f"Too many lines with trailing whitespace: {trailing_whitespace_lines[:5]}" + + # Check for multiple consecutive blank lines + consecutive_blanks = 0 + max_consecutive_blanks = 0 + + for line in lines: + if line.strip() == '': + consecutive_blanks += 1 + max_consecutive_blanks = max(max_consecutive_blanks, consecutive_blanks) + else: + consecutive_blanks = 0 + + assert max_consecutive_blanks <= 3, "Should not have more than 3 consecutive blank lines" + + +if __name__ == "__main__": + pytest.main([__file__, "-v"]) \ No newline at end of file From 18befd2863dc4419ae7c3a66493d0dd6df57a744 Mon Sep 17 00:00:00 2001 From: hexaredecimal Date: Thu, 7 Aug 2025 00:57:02 +0200 Subject: [PATCH 03/48] CanvasFrame: Remove the extra threads --- src/main/java/org/editor/CanvasFrame.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/editor/CanvasFrame.java b/src/main/java/org/editor/CanvasFrame.java index 7315838..96f76cb 100644 --- a/src/main/java/org/editor/CanvasFrame.java +++ b/src/main/java/org/editor/CanvasFrame.java @@ -116,12 +116,8 @@ protected void paintComponent(Graphics g) { g2.setColor(Color.BLACK); gfx = g2; if (start && file != null && code != null) { - SwingUtilities.invokeLater(() -> { AccessFrame.msgs.setText(""); - new Thread(() -> compileFrame()) - .start(); - }); - start = false; + compileFrame(); } drawSelection(g2); @@ -131,6 +127,7 @@ protected void paintComponent(Graphics g) { } private PiccodeValue compileFrame() { + Context.top.resetContext(); var result = Compiler.compile(file, code); return result; } From cb7831dd6f9806f2dfe4dd77c457d32da5248abd Mon Sep 17 00:00:00 2001 From: hexaredecimal Date: Thu, 7 Aug 2025 00:57:29 +0200 Subject: [PATCH 04/48] Piccode: register native functions at the start --- src/main/java/org/piccode/piccode/Piccode.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/piccode/piccode/Piccode.java b/src/main/java/org/piccode/piccode/Piccode.java index 9f2b0c1..7375af2 100644 --- a/src/main/java/org/piccode/piccode/Piccode.java +++ b/src/main/java/org/piccode/piccode/Piccode.java @@ -2,6 +2,7 @@ import org.editor.AccessFrame; import org.editor.EditorWindow; +import org.editor.nativemods.PiccodeGfxModule; import org.piccode.backend.Compiler; import org.piccode.piccodescript.ErrorAsciiKind; @@ -15,7 +16,11 @@ public static void main(String[] args) { Compiler.exitOnError = false; Compiler.errorKind = ErrorAsciiKind.EMACS_COMP_STYLE; Compiler.out = AccessFrame.AccessFrameOutputStream.out; - + initializeNativeAppModules(); EditorWindow.the(); } + + private static void initializeNativeAppModules() { + Compiler.addNativeFunctions(PiccodeGfxModule::addFunctions); + } } From fa110044b2baf907d64524259450f84284a506f8 Mon Sep 17 00:00:00 2001 From: hexaredecimal Date: Thu, 7 Aug 2025 00:58:14 +0200 Subject: [PATCH 05/48] nativemods: The start of piccode specific modules --- .../editor/nativemods/PiccodeGfxModule.java | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 src/main/java/org/editor/nativemods/PiccodeGfxModule.java diff --git a/src/main/java/org/editor/nativemods/PiccodeGfxModule.java b/src/main/java/org/editor/nativemods/PiccodeGfxModule.java new file mode 100644 index 0000000..b57e39a --- /dev/null +++ b/src/main/java/org/editor/nativemods/PiccodeGfxModule.java @@ -0,0 +1,89 @@ +package org.editor.nativemods; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.util.HashMap; +import java.util.List; +import org.editor.CanvasFrame; +import org.piccode.rt.Context; +import org.piccode.rt.PiccodeException; +import org.piccode.rt.PiccodeNumber; +import org.piccode.rt.PiccodeObject; +import org.piccode.rt.PiccodeString; +import org.piccode.rt.PiccodeUnit; +import org.piccode.rt.PiccodeValue; +import org.piccode.rt.PiccodeValue.Type; +import org.piccode.rt.modules.NativeFunctionFactory; + +/** + * + * @author hexaredecimal + */ +public class PiccodeGfxModule { + + public static void addFunctions() { + NativeFunctionFactory.create("get_gfx", List.of(), (args, namedArgs, frame) -> { + var gfx = CanvasFrame.gfx; + var obj = Context.getObject(gfx.hashCode()); + if (obj == null) { + Context.allocate(gfx); + return makeObj(gfx); + } + return makeObj(gfx); + }, null); + + NativeFunctionFactory.create("draw_line", List.of("ctx", "x1", "y1", "x2", "y2"), (args, namedArgs, frame) -> { + var _ctx = namedArgs.get("ctx"); + var _x1 = namedArgs.get("x1"); + var _y1 = namedArgs.get("y1"); + var _x2 = namedArgs.get("x2"); + var _y2 = namedArgs.get("y2"); + + var ctx = frame == null ? + Context.top + : Context.getContextAt(frame); + var caller = ctx.getTopFrame().caller; + + PiccodeValue.verifyType(caller, _ctx, Type.OBJECT); + PiccodeValue.verifyType(caller, _x1, Type.NUMBER); + PiccodeValue.verifyType(caller, _y1, Type.NUMBER); + PiccodeValue.verifyType(caller, _x2, Type.NUMBER); + PiccodeValue.verifyType(caller, _y2, Type.NUMBER); + + var obj = (PiccodeObject) _ctx; + var map = obj.obj; + if (!map.containsKey("hash")) { + throw new PiccodeException(caller.file, caller.line, caller.column, "Context is not an object"); + } + + var _hash = map.get("hash"); + PiccodeValue.verifyType(caller, _hash, Type.NUMBER); + var hash = (int) (double) ((PiccodeNumber) _hash).raw(); + var _gfx = Context.getObject(hash); + if (_gfx == null) { + throw new PiccodeException(caller.file, caller.line, caller.column, "Context is not allocated"); + } + if (!(_gfx instanceof Graphics2D)) { + throw new PiccodeException(caller.file, caller.line, caller.column, "Context is not a correct object. Expected Graphics2D"); + } + + var gfx = (Graphics2D) _gfx; + var x1 = (int) (double) ((PiccodeNumber) _x1).raw(); + var y1 = (int) (double) ((PiccodeNumber) _y1).raw(); + var x2 = (int) (double) ((PiccodeNumber) _x2).raw(); + var y2 = (int) (double) ((PiccodeNumber) _y2).raw(); + + gfx.setColor(Color.black); + gfx.drawRect(x1, y1, x2, y2); + return obj; + }, null); + + } + + private static PiccodeValue makeObj(Graphics2D obj) { + var _obj = new HashMap(); + _obj.put("hash", new PiccodeNumber(obj.hashCode())); + _obj.put("class", new PiccodeString(obj.getClass().getName())); + return new PiccodeObject(_obj); + } +} From 1c90902c578aaeafc40e47154012406e5cfe0d99 Mon Sep 17 00:00:00 2001 From: hexaredecimal Date: Thu, 7 Aug 2025 00:58:52 +0200 Subject: [PATCH 06/48] piccode: The piccode stdlib. This contains functions and modules for the editor only --- piccode/render/context.pics | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 piccode/render/context.pics diff --git a/piccode/render/context.pics b/piccode/render/context.pics new file mode 100644 index 0000000..23fdb26 --- /dev/null +++ b/piccode/render/context.pics @@ -0,0 +1,8 @@ + + +Render :: module { + getContext :: () = pic_nat_get_gfx() + + drawLine :: (ctx, startx, starty, endx, endy) = pic_nat_draw_line(ctx, startx, starty, endx, endy) +} + From cae2694de45b7b1d776dba0453d11bb94b379687 Mon Sep 17 00:00:00 2001 From: hexaredecimal Date: Thu, 7 Aug 2025 00:59:28 +0200 Subject: [PATCH 07/48] pom.xml: Build using master branch --- pom.xml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 79a9f33..0c67325 100644 --- a/pom.xml +++ b/pom.xml @@ -15,6 +15,15 @@ jitpack.io https://jitpack.io + + + true + always + + + always + + @@ -66,7 +75,7 @@ com.github.Glimmr-Lang PiccodeScript - -SNAPSHOT + main-SNAPSHOT From b1723055d47cb00462d490e6042870eb64e93b6b Mon Sep 17 00:00:00 2001 From: hexaredecimal Date: Thu, 7 Aug 2025 11:11:19 +0200 Subject: [PATCH 08/48] nativemods: Use the correct rendering function: drawLine instead of drawRect --- src/main/java/org/editor/nativemods/PiccodeGfxModule.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/editor/nativemods/PiccodeGfxModule.java b/src/main/java/org/editor/nativemods/PiccodeGfxModule.java index b57e39a..aa85c38 100644 --- a/src/main/java/org/editor/nativemods/PiccodeGfxModule.java +++ b/src/main/java/org/editor/nativemods/PiccodeGfxModule.java @@ -74,7 +74,7 @@ public static void addFunctions() { var y2 = (int) (double) ((PiccodeNumber) _y2).raw(); gfx.setColor(Color.black); - gfx.drawRect(x1, y1, x2, y2); + gfx.drawLine(x1, y1, x2, y2); return obj; }, null); From 04132f6f99da2ca71278ca89dcaf5e954e25efe3 Mon Sep 17 00:00:00 2001 From: hexaredecimal Date: Thu, 7 Aug 2025 11:18:07 +0200 Subject: [PATCH 09/48] nativemods: Do not set the color to black when drawing --- src/main/java/org/editor/nativemods/PiccodeGfxModule.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/editor/nativemods/PiccodeGfxModule.java b/src/main/java/org/editor/nativemods/PiccodeGfxModule.java index aa85c38..22987c6 100644 --- a/src/main/java/org/editor/nativemods/PiccodeGfxModule.java +++ b/src/main/java/org/editor/nativemods/PiccodeGfxModule.java @@ -73,7 +73,6 @@ public static void addFunctions() { var x2 = (int) (double) ((PiccodeNumber) _x2).raw(); var y2 = (int) (double) ((PiccodeNumber) _y2).raw(); - gfx.setColor(Color.black); gfx.drawLine(x1, y1, x2, y2); return obj; }, null); From ad7e0eec058f1ad89e87694c3fb0572cd6007ffe Mon Sep 17 00:00:00 2001 From: hexaredecimal Date: Thu, 7 Aug 2025 20:18:58 +0200 Subject: [PATCH 10/48] NewProjectDialog: Adds the new project dialog --- .../org/editor/dialogs/NewProjectDialog.form | 376 +++++++++++++++++ .../org/editor/dialogs/NewProjectDialog.java | 377 ++++++++++++++++++ 2 files changed, 753 insertions(+) create mode 100644 src/main/java/org/editor/dialogs/NewProjectDialog.form create mode 100644 src/main/java/org/editor/dialogs/NewProjectDialog.java diff --git a/src/main/java/org/editor/dialogs/NewProjectDialog.form b/src/main/java/org/editor/dialogs/NewProjectDialog.form new file mode 100644 index 0000000..fcf699d --- /dev/null +++ b/src/main/java/org/editor/dialogs/NewProjectDialog.form @@ -0,0 +1,376 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/org/editor/dialogs/NewProjectDialog.java b/src/main/java/org/editor/dialogs/NewProjectDialog.java new file mode 100644 index 0000000..ad09f00 --- /dev/null +++ b/src/main/java/org/editor/dialogs/NewProjectDialog.java @@ -0,0 +1,377 @@ +package org.editor.dialogs; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.JFileChooser; + +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +/** + * + * @author vulture + */ +public class NewProjectDialog extends javax.swing.JFrame { + + /** + * Creates new form NewProject + */ + + private File selectedFile; + + public NewProjectDialog() { + initComponents(); + this.setResizable(false); + this.setTitle("Create a new project"); + this.hasError = false; + //this.setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + jPanel1 = new javax.swing.JPanel(); + jLabel1 = new javax.swing.JLabel(); + jLabel2 = new javax.swing.JLabel(); + jLabel6 = new javax.swing.JLabel(); + jPanel2 = new javax.swing.JPanel(); + jPanel3 = new javax.swing.JPanel(); + jLabel3 = new javax.swing.JLabel(); + jTextFieldProjectName = new javax.swing.JTextField(); + jLabel4 = new javax.swing.JLabel(); + jTextFieldProjectAuthor = new javax.swing.JTextField(); + jLabelProjectNameError = new javax.swing.JLabel(); + jLabelProjectAuthorError = new javax.swing.JLabel(); + jPanel4 = new javax.swing.JPanel(); + jLabel5 = new javax.swing.JLabel(); + jTextFieldProjectLocation = new javax.swing.JTextField(); + jCheckBox1 = new javax.swing.JCheckBox(); + jButton1 = new javax.swing.JButton(); + jLabelProjectLocationError = new javax.swing.JLabel(); + jCheckBox2 = new javax.swing.JCheckBox(); + jButtonFinish = new javax.swing.JButton(); + jButtonHelp = new javax.swing.JButton(); + jButtonCancel = new javax.swing.JButton(); + + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + setAlwaysOnTop(true); + setLocation(new java.awt.Point(400, 400)); + setResizable(false); + + jPanel1.setBackground(new java.awt.Color(255, 255, 255)); + jPanel1.setBorder(javax.swing.BorderFactory.createEtchedBorder()); + + jLabel1.setFont(new java.awt.Font("Tahoma", 1, 15)); // NOI18N + jLabel1.setText(" STEPS___________"); + + jLabel2.setText(" Add project name
and author(s)"); + + jLabel6.setFont(new java.awt.Font("sansserif", 0, 10)); // NOI18N + jLabel6.setText(" Add project folder name
and create new file system "); + + javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); + jPanel1.setLayout(jPanel1Layout); + jPanel1Layout.setHorizontalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 138, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, 138, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jLabel6, javax.swing.GroupLayout.PREFERRED_SIZE, 138, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap(18, Short.MAX_VALUE)) + ); + jPanel1Layout.setVerticalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 44, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, 47, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(jLabel6, javax.swing.GroupLayout.PREFERRED_SIZE, 47, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + jPanel2.setBorder(javax.swing.BorderFactory.createEtchedBorder()); + + jPanel3.setBorder(javax.swing.BorderFactory.createTitledBorder("Project Information")); + + jLabel3.setText("Project name :"); + + jLabel4.setText("Project author :"); + + jLabelProjectNameError.setForeground(new java.awt.Color(255, 0, 0)); + jLabelProjectNameError.setText("*"); + jLabelProjectNameError.setEnabled(false); + + jLabelProjectAuthorError.setForeground(new java.awt.Color(255, 0, 0)); + jLabelProjectAuthorError.setText("*"); + jLabelProjectAuthorError.setEnabled(false); + + javax.swing.GroupLayout jPanel3Layout = new javax.swing.GroupLayout(jPanel3); + jPanel3.setLayout(jPanel3Layout); + jPanel3Layout.setHorizontalGroup( + jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel3Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel3Layout.createSequentialGroup() + .addComponent(jLabel4) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)) + .addGroup(jPanel3Layout.createSequentialGroup() + .addComponent(jLabel3) + .addGap(13, 13, 13))) + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addComponent(jTextFieldProjectName) + .addComponent(jTextFieldProjectAuthor, javax.swing.GroupLayout.DEFAULT_SIZE, 254, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jLabelProjectNameError) + .addComponent(jLabelProjectAuthorError)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + jPanel3Layout.setVerticalGroup( + jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel3Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabel3) + .addComponent(jTextFieldProjectName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jLabelProjectNameError)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabel4) + .addComponent(jTextFieldProjectAuthor, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jLabelProjectAuthorError)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + jPanel4.setBorder(javax.swing.BorderFactory.createTitledBorder("Project Filesystem")); + + jLabel5.setText("Project location :"); + + jCheckBox1.setText("Create a new folder"); + + jButton1.setText("Select"); + jButton1.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + jButton1ActionPerformed(evt); + } + }); + + jLabelProjectLocationError.setForeground(new java.awt.Color(255, 0, 0)); + jLabelProjectLocationError.setText("Invalid project location"); + jLabelProjectLocationError.setEnabled(false); + + jCheckBox2.setText("Initialize git repo"); + + javax.swing.GroupLayout jPanel4Layout = new javax.swing.GroupLayout(jPanel4); + jPanel4.setLayout(jPanel4Layout); + jPanel4Layout.setHorizontalGroup( + jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel4Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel4Layout.createSequentialGroup() + .addGroup(jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addGroup(jPanel4Layout.createSequentialGroup() + .addComponent(jCheckBox1) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jLabelProjectLocationError)) + .addGroup(jPanel4Layout.createSequentialGroup() + .addComponent(jLabel5) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(jTextFieldProjectLocation, javax.swing.GroupLayout.PREFERRED_SIZE, 227, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(jButton1)) + .addComponent(jCheckBox2)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + jPanel4Layout.setVerticalGroup( + jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel4Layout.createSequentialGroup() + .addGroup(jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabel5) + .addComponent(jTextFieldProjectLocation, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jButton1)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jCheckBox1) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel4Layout.createSequentialGroup() + .addComponent(jLabelProjectLocationError) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 4, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 2, Short.MAX_VALUE) + .addComponent(jCheckBox2) + .addContainerGap()) + ); + + jButtonFinish.setText("Finish"); + jButtonFinish.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + jButtonFinishActionPerformed(evt); + } + }); + + jButtonHelp.setText("Help"); + + jButtonCancel.setText("Cancel"); + jButtonCancel.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + jButtonCancelActionPerformed(evt); + } + }); + + javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2); + jPanel2.setLayout(jPanel2Layout); + jPanel2Layout.setHorizontalGroup( + jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel2Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jPanel3, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jPanel4, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel2Layout.createSequentialGroup() + .addGap(0, 0, Short.MAX_VALUE) + .addComponent(jButtonCancel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jButtonFinish) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jButtonHelp))) + .addContainerGap()) + ); + jPanel2Layout.setVerticalGroup( + jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel2Layout.createSequentialGroup() + .addContainerGap() + .addComponent(jPanel3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel4, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jButtonFinish) + .addComponent(jButtonHelp) + .addComponent(jButtonCancel)) + .addContainerGap()) + ); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addContainerGap()) + ); + + pack(); + }//
//GEN-END:initComponents + + private void jButtonCancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonCancelActionPerformed + this.dispose(); + }//GEN-LAST:event_jButtonCancelActionPerformed + + private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed + JFileChooser fileChooser = new JFileChooser(); + fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + int option = fileChooser.showOpenDialog(null); + + if (option == JFileChooser.APPROVE_OPTION) { + selectedFile = fileChooser.getSelectedFile(); + jTextFieldProjectLocation.setText(selectedFile.getPath()); + } + }//GEN-LAST:event_jButton1ActionPerformed + + private void jButtonFinishActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonFinishActionPerformed + if (jTextFieldProjectName.getText().isEmpty()) { + jLabelProjectNameError.setEnabled(true); + return; + } else { + jLabelProjectNameError.setEnabled(false); + } + + if (jTextFieldProjectAuthor.getText().isEmpty()) { + jLabelProjectAuthorError.setEnabled(true); + return; + } else { + jLabelProjectAuthorError.setEnabled(false); + } + + if(jTextFieldProjectLocation.getText().isEmpty()) { + jLabelProjectLocationError.setEnabled(true); + jLabelProjectLocationError.setText("Invalid project location"); + } else { + + if (selectedFile != null && selectedFile.exists() == false) { + jLabelProjectLocationError.setEnabled(true); + jLabelProjectLocationError.setText("Selected directory does not exist"); + return; + } else if (selectedFile == null) { + File tmp = new File(jTextFieldProjectLocation.getText()); + if(tmp.exists() == false) { + jLabelProjectLocationError.setEnabled(true); + jLabelProjectLocationError.setText("Selected directory does not exist"); + return; + } + } else { + // continue by disableing the errors + jLabelProjectLocationError.setText("Invalid project location"); + jLabelProjectLocationError.setEnabled(false); + } + } + + String projectName = jTextFieldProjectName.getText(); + String projectAuthor = jTextFieldProjectAuthor.getText(); + String projectPath = jTextFieldProjectLocation.getText(); + + + + }//GEN-LAST:event_jButtonFinishActionPerformed + + private boolean hasError; + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton jButton1; + private javax.swing.JButton jButtonCancel; + private javax.swing.JButton jButtonFinish; + private javax.swing.JButton jButtonHelp; + private javax.swing.JCheckBox jCheckBox1; + private javax.swing.JCheckBox jCheckBox2; + private javax.swing.JLabel jLabel1; + private javax.swing.JLabel jLabel2; + private javax.swing.JLabel jLabel3; + private javax.swing.JLabel jLabel4; + private javax.swing.JLabel jLabel5; + private javax.swing.JLabel jLabel6; + private javax.swing.JLabel jLabelProjectAuthorError; + private javax.swing.JLabel jLabelProjectLocationError; + private javax.swing.JLabel jLabelProjectNameError; + private javax.swing.JPanel jPanel1; + private javax.swing.JPanel jPanel2; + private javax.swing.JPanel jPanel3; + private javax.swing.JPanel jPanel4; + private javax.swing.JTextField jTextFieldProjectAuthor; + private javax.swing.JTextField jTextFieldProjectLocation; + private javax.swing.JTextField jTextFieldProjectName; + // End of variables declaration//GEN-END:variables +} From 3b60e9a9ba8aad38d919f035ae0f0cea39e9d126 Mon Sep 17 00:00:00 2001 From: hexaredecimal Date: Thu, 7 Aug 2025 20:19:57 +0200 Subject: [PATCH 11/48] examples: Adds the 1st example --- examples/starrect.pics | 43 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 examples/starrect.pics diff --git a/examples/starrect.pics b/examples/starrect.pics new file mode 100644 index 0000000..f8b14b6 --- /dev/null +++ b/examples/starrect.pics @@ -0,0 +1,43 @@ + +IO :: import std.io +Virtual :: import std.virtual +Render :: import piccode.render + +drawStar :: (ctx, padding=0) = + ctx + |> Render::drawLine(50+padding, 50+padding, 150-padding, 150-padding) + |> Render::drawLine(150-padding, 50+padding, 50+padding, 150-padding) + |> Render::drawLine(50+padding, 100, 150-padding, 100) + |> Render::drawLine(100, 50+padding, 100, 150-padding) + +drawRect :: (ctx, x, y, w, h) = + ctx + |> Render::drawLine(x, y, x + w, y) + |> Render::drawLine(x, y + h, x + w, y + h) + |> Render::drawLine(x, y, x, y + w) + |> Render::drawLine(x + w, y, x + w, y + h) + +drawDepth :: (ctx) = + ctx + |> Render::drawLine(150, 50, 200, 70) + |> Render::drawLine(150, 150, 200, 170) + |> Render::drawLine(50, 150, 100, 170) + +drawBackLines :: (ctx) = + ctx + |> Render::drawLine(100, 170, 200, 170) + |> Render::drawLine(200, 70, 200, 170) + +main :: () = + let + ctx := Render::getContext() + in + ctx + |> drawRect(50, 50, 100, 100) + |> drawDepth + |> drawBackLines + |> drawStar(10) + + + + From 76f966e3cf974263dd32669e9350e42089490e36 Mon Sep 17 00:00:00 2001 From: hexaredecimal Date: Thu, 7 Aug 2025 20:20:36 +0200 Subject: [PATCH 12/48] piccode: Add documentation to the stdlib --- piccode/render/context.pics | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/piccode/render/context.pics b/piccode/render/context.pics index 23fdb26..15371a1 100644 --- a/piccode/render/context.pics +++ b/piccode/render/context.pics @@ -1,8 +1,29 @@ - +// Module: Render +// Functions for working with the editor render context Render :: module { + // Function: getContext + // returns the render context (A handle to the Render window on the screen) + // + // Parameters: + // None + // + // Returns: + // - (Object) an handler to the Graphics2D. getContext :: () = pic_nat_get_gfx() - + + // Function: drawLine + // Draws a line inside the specified context, based on the provided coordinates + // + // Parameters: + // ctx - (Object) The graphic context + // startx - (Number) The start x position + // starty - (Number) The start y position + // endx - (Number) The end x position + // endy - (Number) The end y position + // + // Returns: + // - (Object) A modified context with the rendered element. drawLine :: (ctx, startx, starty, endx, endy) = pic_nat_draw_line(ctx, startx, starty, endx, endy) } From 010a831fdb8d82bf3bea2b62fab8b7bb91334976 Mon Sep 17 00:00:00 2001 From: hexaredecimal Date: Fri, 8 Aug 2025 22:03:58 +0200 Subject: [PATCH 13/48] editor: Use reference types for working with graphic contexts --- .../editor/nativemods/PiccodeGfxModule.java | 88 +++++---- .../editor/nativemods/PiccodePenModule.java | 170 ++++++++++++++++++ 2 files changed, 213 insertions(+), 45 deletions(-) create mode 100644 src/main/java/org/editor/nativemods/PiccodePenModule.java diff --git a/src/main/java/org/editor/nativemods/PiccodeGfxModule.java b/src/main/java/org/editor/nativemods/PiccodeGfxModule.java index 22987c6..be509d4 100644 --- a/src/main/java/org/editor/nativemods/PiccodeGfxModule.java +++ b/src/main/java/org/editor/nativemods/PiccodeGfxModule.java @@ -9,6 +9,7 @@ import org.piccode.rt.PiccodeException; import org.piccode.rt.PiccodeNumber; import org.piccode.rt.PiccodeObject; +import org.piccode.rt.PiccodeReference; import org.piccode.rt.PiccodeString; import org.piccode.rt.PiccodeUnit; import org.piccode.rt.PiccodeValue; @@ -24,65 +25,62 @@ public class PiccodeGfxModule { public static void addFunctions() { NativeFunctionFactory.create("get_gfx", List.of(), (args, namedArgs, frame) -> { var gfx = CanvasFrame.gfx; - var obj = Context.getObject(gfx.hashCode()); - if (obj == null) { - Context.allocate(gfx); - return makeObj(gfx); - } - return makeObj(gfx); + return new PiccodeReference(gfx); }, null); - NativeFunctionFactory.create("draw_line", List.of("ctx", "x1", "y1", "x2", "y2"), (args, namedArgs, frame) -> { + NativeFunctionFactory.create("gfx_from_rect", List.of("ctx", "x", "y", "w", "h"), (args, namedArgs, frame) -> { var _ctx = namedArgs.get("ctx"); - var _x1 = namedArgs.get("x1"); - var _y1 = namedArgs.get("y1"); - var _x2 = namedArgs.get("x2"); - var _y2 = namedArgs.get("y2"); + var x = namedArgs.get("x"); + var y = namedArgs.get("y"); + var w = namedArgs.get("w"); + var h = namedArgs.get("h"); - var ctx = frame == null ? - Context.top - : Context.getContextAt(frame); + var ctx = frame == null + ? Context.top + : Context.getContextAt(frame); var caller = ctx.getTopFrame().caller; - - PiccodeValue.verifyType(caller, _ctx, Type.OBJECT); - PiccodeValue.verifyType(caller, _x1, Type.NUMBER); - PiccodeValue.verifyType(caller, _y1, Type.NUMBER); - PiccodeValue.verifyType(caller, _x2, Type.NUMBER); - PiccodeValue.verifyType(caller, _y2, Type.NUMBER); - var obj = (PiccodeObject) _ctx; - var map = obj.obj; - if (!map.containsKey("hash")) { - throw new PiccodeException(caller.file, caller.line, caller.column, "Context is not an object"); - } - - var _hash = map.get("hash"); - PiccodeValue.verifyType(caller, _hash, Type.NUMBER); - var hash = (int) (double) ((PiccodeNumber) _hash).raw(); - var _gfx = Context.getObject(hash); - if (_gfx == null) { - throw new PiccodeException(caller.file, caller.line, caller.column, "Context is not allocated"); + PiccodeValue.verifyType(caller, _ctx, Type.REFERENCE); + PiccodeValue.verifyType(caller, x, Type.NUMBER); + PiccodeValue.verifyType(caller, y, Type.NUMBER); + PiccodeValue.verifyType(caller, w, Type.NUMBER); + PiccodeValue.verifyType(caller, h, Type.NUMBER); + + var obj = (PiccodeReference) _ctx; + var _gfx = obj.deref(); + if (!(_gfx instanceof Graphics2D)) { + throw new PiccodeException(caller.file, caller.line, caller.column, "Context is not a correct object. Expected Graphics2D"); } + + var gfx = (Graphics2D) _gfx; + var _x = (int) (double) ((PiccodeNumber) x).raw(); + var _y = (int) (double) ((PiccodeNumber) y).raw(); + var _w = (int) (double) ((PiccodeNumber) w).raw(); + var _h = (int) (double) ((PiccodeNumber) h).raw(); + + var gfx2 = (Graphics2D) gfx.create(_x, _y, _w, _h); + return new PiccodeReference(gfx2); + }, null); + NativeFunctionFactory.create("gfx_from", List.of("ctx"), (args, namedArgs, frame) -> { + var _ctx = namedArgs.get("ctx"); + + var ctx = frame == null + ? Context.top + : Context.getContextAt(frame); + var caller = ctx.getTopFrame().caller; + + PiccodeValue.verifyType(caller, _ctx, Type.REFERENCE); + var obj = (PiccodeReference) _ctx; + var _gfx = obj.deref(); if (!(_gfx instanceof Graphics2D)) { throw new PiccodeException(caller.file, caller.line, caller.column, "Context is not a correct object. Expected Graphics2D"); } var gfx = (Graphics2D) _gfx; - var x1 = (int) (double) ((PiccodeNumber) _x1).raw(); - var y1 = (int) (double) ((PiccodeNumber) _y1).raw(); - var x2 = (int) (double) ((PiccodeNumber) _x2).raw(); - var y2 = (int) (double) ((PiccodeNumber) _y2).raw(); - gfx.drawLine(x1, y1, x2, y2); - return obj; + var gfx2 = (Graphics2D) gfx.create(); + return new PiccodeReference(gfx2); }, null); - } - private static PiccodeValue makeObj(Graphics2D obj) { - var _obj = new HashMap(); - _obj.put("hash", new PiccodeNumber(obj.hashCode())); - _obj.put("class", new PiccodeString(obj.getClass().getName())); - return new PiccodeObject(_obj); - } } diff --git a/src/main/java/org/editor/nativemods/PiccodePenModule.java b/src/main/java/org/editor/nativemods/PiccodePenModule.java new file mode 100644 index 0000000..11107c0 --- /dev/null +++ b/src/main/java/org/editor/nativemods/PiccodePenModule.java @@ -0,0 +1,170 @@ +package org.editor.nativemods; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.util.HashMap; +import java.util.List; +import org.editor.CanvasFrame; +import org.piccode.rt.Context; +import org.piccode.rt.PiccodeException; +import org.piccode.rt.PiccodeNumber; +import org.piccode.rt.PiccodeObject; +import org.piccode.rt.PiccodeReference; +import org.piccode.rt.PiccodeString; +import org.piccode.rt.PiccodeUnit; +import org.piccode.rt.PiccodeValue; +import org.piccode.rt.PiccodeValue.Type; +import org.piccode.rt.modules.NativeFunctionFactory; + +/** + * + * @author hexaredecimal + */ +public class PiccodePenModule { + + public static void addFunctions() { + + NativeFunctionFactory.create("draw_line", List.of("ctx", "x1", "y1", "x2", "y2"), (args, namedArgs, frame) -> { + var _ctx = namedArgs.get("ctx"); + var _x1 = namedArgs.get("x1"); + var _y1 = namedArgs.get("y1"); + var _x2 = namedArgs.get("x2"); + var _y2 = namedArgs.get("y2"); + + var ctx = frame == null ? + Context.top + : Context.getContextAt(frame); + var caller = ctx.getTopFrame().caller; + + PiccodeValue.verifyType(caller, _ctx, Type.REFERENCE); + PiccodeValue.verifyType(caller, _x1, Type.NUMBER); + PiccodeValue.verifyType(caller, _y1, Type.NUMBER); + PiccodeValue.verifyType(caller, _x2, Type.NUMBER); + PiccodeValue.verifyType(caller, _y2, Type.NUMBER); + + var obj = (PiccodeReference) _ctx; + var _gfx = obj.deref(); + if (!(_gfx instanceof Graphics2D)) { + throw new PiccodeException(caller.file, caller.line, caller.column, "Context is not a correct object. Expected Graphics2D"); + } + + var gfx = (Graphics2D) _gfx; + var x1 = (int) (double) ((PiccodeNumber) _x1).raw(); + var y1 = (int) (double) ((PiccodeNumber) _y1).raw(); + var x2 = (int) (double) ((PiccodeNumber) _x2).raw(); + var y2 = (int) (double) ((PiccodeNumber) _y2).raw(); + + gfx.drawLine(x1, y1, x2, y2); + return obj; + }, null); + + NativeFunctionFactory.create("draw_rect", List.of("ctx", "x", "y", "w", "h"), (args, namedArgs, frame) -> { + var _ctx = namedArgs.get("ctx"); + var x = namedArgs.get("x"); + var y = namedArgs.get("y"); + var w = namedArgs.get("w"); + var h = namedArgs.get("h"); + + var ctx = frame == null ? + Context.top + : Context.getContextAt(frame); + var caller = ctx.getTopFrame().caller; + + PiccodeValue.verifyType(caller, _ctx, Type.REFERENCE); + PiccodeValue.verifyType(caller, x, Type.NUMBER); + PiccodeValue.verifyType(caller, y, Type.NUMBER); + PiccodeValue.verifyType(caller, w, Type.NUMBER); + PiccodeValue.verifyType(caller, h, Type.NUMBER); + + var obj = (PiccodeReference) _ctx; + var _gfx = obj.deref(); + if (!(_gfx instanceof Graphics2D)) { + throw new PiccodeException(caller.file, caller.line, caller.column, "Context is not a correct object. Expected Graphics2D"); + } + + var gfx = (Graphics2D) _gfx; + var _x = (int) (double) ((PiccodeNumber) x).raw(); + var _y = (int) (double) ((PiccodeNumber) y).raw(); + var _w = (int) (double) ((PiccodeNumber) w).raw(); + var _h = (int) (double) ((PiccodeNumber) h).raw(); + + gfx.drawRect(_x, _y, _w, _h); + return obj; + }, null); + + NativeFunctionFactory.create("draw_round_rect", List.of("ctx", "x", "y", "w", "h", "aw", "ah"), (args, namedArgs, frame) -> { + var _ctx = namedArgs.get("ctx"); + var x = namedArgs.get("x"); + var y = namedArgs.get("y"); + var w = namedArgs.get("w"); + var h = namedArgs.get("h"); + var aw = namedArgs.get("aw"); + var ah = namedArgs.get("ah"); + + var ctx = frame == null ? + Context.top + : Context.getContextAt(frame); + var caller = ctx.getTopFrame().caller; + + PiccodeValue.verifyType(caller, _ctx, Type.REFERENCE); + PiccodeValue.verifyType(caller, x, Type.NUMBER); + PiccodeValue.verifyType(caller, y, Type.NUMBER); + PiccodeValue.verifyType(caller, w, Type.NUMBER); + PiccodeValue.verifyType(caller, h, Type.NUMBER); + PiccodeValue.verifyType(caller, aw, Type.NUMBER); + PiccodeValue.verifyType(caller, ah, Type.NUMBER); + + var obj = (PiccodeReference) _ctx; + var _gfx = obj.deref(); + if (!(_gfx instanceof Graphics2D)) { + throw new PiccodeException(caller.file, caller.line, caller.column, "Context is not a correct object. Expected Graphics2D"); + } + + var gfx = (Graphics2D) _gfx; + var _x = (int) (double) ((PiccodeNumber) x).raw(); + var _y = (int) (double) ((PiccodeNumber) y).raw(); + var _w = (int) (double) ((PiccodeNumber) w).raw(); + var _h = (int) (double) ((PiccodeNumber) h).raw(); + var _aw = (int) (double) ((PiccodeNumber) aw).raw(); + var _ah = (int) (double) ((PiccodeNumber) ah).raw(); + + gfx.drawRoundRect(_x, _y, _w, _h, _aw, _ah); + return obj; + }, null); + + NativeFunctionFactory.create("draw_oval", List.of("ctx", "x", "y", "w", "h"), (args, namedArgs, frame) -> { + var _ctx = namedArgs.get("ctx"); + var x = namedArgs.get("x"); + var y = namedArgs.get("y"); + var w = namedArgs.get("w"); + var h = namedArgs.get("h"); + + var ctx = frame == null ? + Context.top + : Context.getContextAt(frame); + var caller = ctx.getTopFrame().caller; + + PiccodeValue.verifyType(caller, _ctx, Type.REFERENCE); + PiccodeValue.verifyType(caller, x, Type.NUMBER); + PiccodeValue.verifyType(caller, y, Type.NUMBER); + PiccodeValue.verifyType(caller, w, Type.NUMBER); + PiccodeValue.verifyType(caller, h, Type.NUMBER); + + var obj = (PiccodeReference) _ctx; + var _gfx = obj.deref(); + if (!(_gfx instanceof Graphics2D)) { + throw new PiccodeException(caller.file, caller.line, caller.column, "Context is not a correct object. Expected Graphics2D"); + } + + var gfx = (Graphics2D) _gfx; + var _x = (int) (double) ((PiccodeNumber) x).raw(); + var _y = (int) (double) ((PiccodeNumber) y).raw(); + var _w = (int) (double) ((PiccodeNumber) w).raw(); + var _h = (int) (double) ((PiccodeNumber) h).raw(); + + gfx.drawOval(_x, _y, _w, _h); + return obj; + }, null); + } + +} From 27f95b4376b35a34e256d662f9b17f0357c6b193 Mon Sep 17 00:00:00 2001 From: hexaredecimal Date: Fri, 8 Aug 2025 22:05:01 +0200 Subject: [PATCH 14/48] piccode: Fixes the API to make it clear --- piccode/context/ctx.pics | 30 ++++++++++++++++++ piccode/pen/draw.pics | 63 +++++++++++++++++++++++++++++++++++++ piccode/render/context.pics | 15 +-------- 3 files changed, 94 insertions(+), 14 deletions(-) create mode 100644 piccode/context/ctx.pics create mode 100644 piccode/pen/draw.pics diff --git a/piccode/context/ctx.pics b/piccode/context/ctx.pics new file mode 100644 index 0000000..afbafd0 --- /dev/null +++ b/piccode/context/ctx.pics @@ -0,0 +1,30 @@ + +// Module: Context +// Contains functions for creating contexts +Context :: module { + + // Function: fromRect + // Creates a new context based on the one provided + // + // Parameters: + // ctx - (Reference) The graphic context + // x - (Number) The x position + // y - (Number) The y position + // w - (Number) The width + // h - (Number) The height + // + // Returns: + // - (Reference) A modified context with the rendered element. + fromRect :: (ctx, x, y, w, h) = pic_nat_from_rect(ctx, x, y, w, h) + + // Function: from + // Creates a new context based on the one provided + // + // Parameters: + // ctx - (Reference) The graphic context + // + // Returns: + // - (Reference) A modified context with the rendered element. + from:: (ctx) = pic_nat_from_rect(ctx) + +} diff --git a/piccode/pen/draw.pics b/piccode/pen/draw.pics new file mode 100644 index 0000000..7c77a94 --- /dev/null +++ b/piccode/pen/draw.pics @@ -0,0 +1,63 @@ + +Pen :: module { + + // Function: drawLine + // Draws a line inside the specified context, based on the provided coordinates + // + // Parameters: + // ctx - (Reference) The graphic context + // startx - (Number) The start x position + // starty - (Number) The start y position + // endx - (Number) The end x position + // endy - (Number) The end y position + // + // Returns: + // - (Reference) A modified context with the rendered element. + drawLine :: (ctx, startx, starty, endx, endy) = pic_nat_draw_line(ctx, startx, starty, endx, endy) + + // Function: drawRect + // Draws a rect inside the specified context, based on the provided coordinates + // + // Parameters: + // ctx - (Reference) The graphic context + // x - (Number) The x position + // y - (Number) The y position + // w - (Number) The width + // h - (Number) The height + // + // Returns: + // - (Reference) A modified context with the rendered element. + drawRect :: (ctx, x, y, w, h) = pic_nat_draw_rect(ctx, x, y, w, h) + + // Function: drawRoundRect + // Draws a rect inside the specified context, based on the provided coordinates + // + // Parameters: + // ctx - (Reference) The graphic context + // x - (Number) The x position + // y - (Number) The y position + // w - (Number) The width + // h - (Number) The height + // aw - (Number) The arc width + // ah - (Number) The arc height + // + // Returns: + // - (Reference) A modified context with the rendered element. + drawRoundRect :: (ctx, x, y, w, h, aw, ah) = pic_nat_draw_round_rect(ctx, x, y, w, h, aw, ah) + + // Function: drawOval + // Draws a rect inside the specified context, based on the provided coordinates + // + // Parameters: + // ctx - (Reference) The graphic context + // x - (Number) The x position + // y - (Number) The y position + // w - (Number) The width + // h - (Number) The height + // + // Returns: + // - (Reference) A modified context with the rendered element. + drawOval :: (ctx, x, y, w, h) = pic_nat_draw_oval(ctx, x, y, w, h) + +} + diff --git a/piccode/render/context.pics b/piccode/render/context.pics index 15371a1..bfd9883 100644 --- a/piccode/render/context.pics +++ b/piccode/render/context.pics @@ -9,21 +9,8 @@ Render :: module { // None // // Returns: - // - (Object) an handler to the Graphics2D. + // - (Reference) an handler to the Graphics2D. getContext :: () = pic_nat_get_gfx() - // Function: drawLine - // Draws a line inside the specified context, based on the provided coordinates - // - // Parameters: - // ctx - (Object) The graphic context - // startx - (Number) The start x position - // starty - (Number) The start y position - // endx - (Number) The end x position - // endy - (Number) The end y position - // - // Returns: - // - (Object) A modified context with the rendered element. - drawLine :: (ctx, startx, starty, endx, endy) = pic_nat_draw_line(ctx, startx, starty, endx, endy) } From 6109dfb5955814aaa1a4033cefb0b5a7f57ae3d4 Mon Sep 17 00:00:00 2001 From: hexaredecimal Date: Fri, 8 Aug 2025 22:06:11 +0200 Subject: [PATCH 15/48] examples: Updates the example to reflect the lates changes --- examples/starrect.pics | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/examples/starrect.pics b/examples/starrect.pics index f8b14b6..4e35fa6 100644 --- a/examples/starrect.pics +++ b/examples/starrect.pics @@ -2,31 +2,32 @@ IO :: import std.io Virtual :: import std.virtual Render :: import piccode.render +Pen :: import piccode.pen drawStar :: (ctx, padding=0) = ctx - |> Render::drawLine(50+padding, 50+padding, 150-padding, 150-padding) - |> Render::drawLine(150-padding, 50+padding, 50+padding, 150-padding) - |> Render::drawLine(50+padding, 100, 150-padding, 100) - |> Render::drawLine(100, 50+padding, 100, 150-padding) + |> Pen::drawLine(50+padding, 50+padding, 150-padding, 150-padding) + |> Pen::drawLine(150-padding, 50+padding, 50+padding, 150-padding) + |> Pen::drawLine(50+padding, 100, 150-padding, 100) + |> Pen::drawLine(100, 50+padding, 100, 150-padding) drawRect :: (ctx, x, y, w, h) = ctx - |> Render::drawLine(x, y, x + w, y) - |> Render::drawLine(x, y + h, x + w, y + h) - |> Render::drawLine(x, y, x, y + w) - |> Render::drawLine(x + w, y, x + w, y + h) + |> Pen::drawLine(x, y, x + w, y) + |> Pen::drawLine(x, y + h, x + w, y + h) + |> Pen::drawLine(x, y, x, y + w) + |> Pen::drawLine(x + w, y, x + w, y + h) drawDepth :: (ctx) = ctx - |> Render::drawLine(150, 50, 200, 70) - |> Render::drawLine(150, 150, 200, 170) - |> Render::drawLine(50, 150, 100, 170) + |> Pen::drawLine(150, 50, 200, 70) + |> Pen::drawLine(150, 150, 200, 170) + |> Pen::drawLine(50, 150, 100, 170) drawBackLines :: (ctx) = ctx - |> Render::drawLine(100, 170, 200, 170) - |> Render::drawLine(200, 70, 200, 170) + |> Pen::drawLine(100, 170, 200, 170) + |> Pen::drawLine(200, 70, 200, 170) main :: () = let From 38de5869675165e2620a7e0902d8f31df1195b09 Mon Sep 17 00:00:00 2001 From: hexaredecimal Date: Fri, 8 Aug 2025 22:28:31 +0200 Subject: [PATCH 16/48] piccode: Fix mistakes --- piccode/context/ctx.pics | 17 +++++++++++++---- piccode/pen/draw.pics | 2 +- piccode/render/context.pics | 2 +- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/piccode/context/ctx.pics b/piccode/context/ctx.pics index afbafd0..302b808 100644 --- a/piccode/context/ctx.pics +++ b/piccode/context/ctx.pics @@ -14,8 +14,8 @@ Context :: module { // h - (Number) The height // // Returns: - // - (Reference) A modified context with the rendered element. - fromRect :: (ctx, x, y, w, h) = pic_nat_from_rect(ctx, x, y, w, h) + // - (Reference) A new graphics sub-context derived from the given context. + fromRect :: (ctx, x, y, w, h) = pic_nat_gfx_from_rect(ctx, x, y, w, h) // Function: from // Creates a new context based on the one provided @@ -24,7 +24,16 @@ Context :: module { // ctx - (Reference) The graphic context // // Returns: - // - (Reference) A modified context with the rendered element. - from:: (ctx) = pic_nat_from_rect(ctx) + // - (Reference) A new graphics context derived from the given context. + from :: (ctx) = pic_nat_gfx_from(ctx) + // Function: drop + // Frees the given context + // + // Parameters: + // ctx - (Reference) The graphic context + // + // Returns: + // - (Unit) Nothing + drop :: (ctx) = pic_nat_gfx_(ctx) } diff --git a/piccode/pen/draw.pics b/piccode/pen/draw.pics index 7c77a94..7f14334 100644 --- a/piccode/pen/draw.pics +++ b/piccode/pen/draw.pics @@ -30,7 +30,7 @@ Pen :: module { drawRect :: (ctx, x, y, w, h) = pic_nat_draw_rect(ctx, x, y, w, h) // Function: drawRoundRect - // Draws a rect inside the specified context, based on the provided coordinates + // Draws a rounded rectangle inside the specified context, based on the provided coordinates // // Parameters: // ctx - (Reference) The graphic context diff --git a/piccode/render/context.pics b/piccode/render/context.pics index bfd9883..3c791c8 100644 --- a/piccode/render/context.pics +++ b/piccode/render/context.pics @@ -9,7 +9,7 @@ Render :: module { // None // // Returns: - // - (Reference) an handler to the Graphics2D. + // - (Reference) a handler to the Graphics2D. getContext :: () = pic_nat_get_gfx() } From b9795d319db074206fd15c9d3a38fa42732ae532 Mon Sep 17 00:00:00 2001 From: hexaredecimal Date: Fri, 8 Aug 2025 22:29:05 +0200 Subject: [PATCH 17/48] Piccode: Register the gfx module --- src/main/java/org/piccode/piccode/Piccode.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/piccode/piccode/Piccode.java b/src/main/java/org/piccode/piccode/Piccode.java index 7375af2..ba34188 100644 --- a/src/main/java/org/piccode/piccode/Piccode.java +++ b/src/main/java/org/piccode/piccode/Piccode.java @@ -3,6 +3,7 @@ import org.editor.AccessFrame; import org.editor.EditorWindow; import org.editor.nativemods.PiccodeGfxModule; +import org.editor.nativemods.PiccodePenModule; import org.piccode.backend.Compiler; import org.piccode.piccodescript.ErrorAsciiKind; @@ -22,5 +23,6 @@ public static void main(String[] args) { private static void initializeNativeAppModules() { Compiler.addNativeFunctions(PiccodeGfxModule::addFunctions); + Compiler.addNativeFunctions(PiccodePenModule::addFunctions); } } From fcbeba12038a854f4a8e5fb18545c1039a7973e8 Mon Sep 17 00:00:00 2001 From: hexaredecimal Date: Fri, 8 Aug 2025 22:29:29 +0200 Subject: [PATCH 18/48] editor: Fixed mistakes --- .../editor/nativemods/PiccodeGfxModule.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/main/java/org/editor/nativemods/PiccodeGfxModule.java b/src/main/java/org/editor/nativemods/PiccodeGfxModule.java index be509d4..6218fb8 100644 --- a/src/main/java/org/editor/nativemods/PiccodeGfxModule.java +++ b/src/main/java/org/editor/nativemods/PiccodeGfxModule.java @@ -81,6 +81,26 @@ public static void addFunctions() { var gfx2 = (Graphics2D) gfx.create(); return new PiccodeReference(gfx2); }, null); + + NativeFunctionFactory.create("gfx_drop", List.of("ctx"), (args, namedArgs, frame) -> { + var _ctx = namedArgs.get("ctx"); + + var ctx = frame == null + ? Context.top + : Context.getContextAt(frame); + var caller = ctx.getTopFrame().caller; + + PiccodeValue.verifyType(caller, _ctx, Type.REFERENCE); + var obj = (PiccodeReference) _ctx; + var _gfx = obj.deref(); + if (!(_gfx instanceof Graphics2D)) { + throw new PiccodeException(caller.file, caller.line, caller.column, "Context is not a correct object. Expected Graphics2D"); + } + + var gfx = (Graphics2D) _gfx; + gfx.dispose(); + return new PiccodeUnit(); + }, null); } } From 122def7bb3e7cf23396c02a5e79e8991be152cae Mon Sep 17 00:00:00 2001 From: hexaredecimal Date: Sat, 9 Aug 2025 11:25:51 +0200 Subject: [PATCH 19/48] editor: Fix the rampant memory usage that was caused by compiling per frame --- src/main/java/org/editor/CanvasFrame.java | 49 +++++--- .../java/org/editor/events/AccessEvents.java | 4 +- .../PiccodeBrushedMetalFilterModule.java | 112 ++++++++++++++++++ .../nativemods/PiccodeFilterModule.java | 57 +++++++++ .../editor/nativemods/PiccodeImageModule.java | 92 ++++++++++++++ 5 files changed, 294 insertions(+), 20 deletions(-) create mode 100644 src/main/java/org/editor/nativemods/PiccodeBrushedMetalFilterModule.java create mode 100644 src/main/java/org/editor/nativemods/PiccodeFilterModule.java create mode 100644 src/main/java/org/editor/nativemods/PiccodeImageModule.java diff --git a/src/main/java/org/editor/CanvasFrame.java b/src/main/java/org/editor/CanvasFrame.java index 96f76cb..594f720 100644 --- a/src/main/java/org/editor/CanvasFrame.java +++ b/src/main/java/org/editor/CanvasFrame.java @@ -2,6 +2,7 @@ import com.vlsolutions.swing.docking.DockKey; import com.vlsolutions.swing.docking.Dockable; +import java.awt.AlphaComposite; import java.awt.BasicStroke; import java.awt.BorderLayout; import java.awt.Color; @@ -21,6 +22,7 @@ import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.List; +import java.util.function.Supplier; import javax.swing.JPanel; import javax.swing.SwingUtilities; import javax.swing.Timer; @@ -46,6 +48,7 @@ public class CanvasFrame extends JPanel implements MouseListener, MouseMotionLis private int lastMouseX, lastMouseY; private BufferedImage gridImage; + private BufferedImage render; private Point lastDragPoint; public static Graphics2D gfx = null; private long lastTime; @@ -66,17 +69,13 @@ public class CanvasFrame extends JPanel implements MouseListener, MouseMotionLis private static CanvasFrame _the = null; private DockKey key = new DockKey("canvas"); - public static String code = null; - public static String file = null; - public static boolean start = false; - private CanvasFrame() { super(new BorderLayout()); this.setBackground(new Color(18, 18, 18)); this.addMouseListener(this); this.addMouseMotionListener(this); drawGrid(); - setPreferredSize(new Dimension(getWidth(), getHeight())); + compile(() -> null); Timer timer = new Timer(16, new ActionListener() { public void actionPerformed(ActionEvent e) { repaint(getVisibleRect()); @@ -108,30 +107,21 @@ protected void paintComponent(Graphics g) { Graphics2D g2 = (Graphics2D) g; drawGrid(); - g2.drawImage(gridImage, 0, 0, null); // Smooth rendering g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2.setColor(Color.BLACK); - gfx = g2; - if (start && file != null && code != null) { - AccessFrame.msgs.setText(""); - compileFrame(); - } + if (render != null) { + g2.drawImage(render, 0, 0, null); + } drawSelection(g2); if (showHighlight) { drawCrosshair(g2); } } - private PiccodeValue compileFrame() { - Context.top.resetContext(); - var result = Compiler.compile(file, code); - return result; - } - private void drawSelection(Graphics2D g2) { if (selecting && selectionStart != null && selectionEnd != null) { Point start = selectionStart; @@ -306,8 +296,33 @@ private void drawGrid() { lastGridOffsetX = offsetX; lastGridOffsetY = offsetY; + g2.dispose(); + } + + public void compile(Supplier fx) { + int width = getWidth(); + int height = getHeight(); + if (width <= 0 || height <= 0) { + return; + } + + render = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + + // Get the Graphics2D object + gfx = render.createGraphics(); + + // Enable transparency by drawing a fully transparent background + gfx.setComposite(AlphaComposite.Clear); + gfx.fillRect(0, 0, width, height); + + gfx.setColor(Color.BLACK); + // Switch back to normal composite mode for drawing + gfx.setComposite(AlphaComposite.SrcOver); + + fx.get(); } + @Override public void mouseClicked(MouseEvent e) { } diff --git a/src/main/java/org/editor/events/AccessEvents.java b/src/main/java/org/editor/events/AccessEvents.java index 5b2f6da..41503e0 100644 --- a/src/main/java/org/editor/events/AccessEvents.java +++ b/src/main/java/org/editor/events/AccessEvents.java @@ -29,9 +29,7 @@ public static void compileAndRender(ActionEvent e) { var file = ed.file.toString(); var code = ed.textArea.getText(); - CanvasFrame.file = file; - CanvasFrame.code = code; - CanvasFrame.start = true; + CanvasFrame.the().compile(() -> Compiler.compile(file, code)); AccessFrame.writeSuccess("Compilation started: "); } diff --git a/src/main/java/org/editor/nativemods/PiccodeBrushedMetalFilterModule.java b/src/main/java/org/editor/nativemods/PiccodeBrushedMetalFilterModule.java new file mode 100644 index 0000000..f0e0843 --- /dev/null +++ b/src/main/java/org/editor/nativemods/PiccodeBrushedMetalFilterModule.java @@ -0,0 +1,112 @@ +package org.editor.nativemods; + +import com.jhlabs.image.BrushedMetalFilter; +import java.awt.Color; +import java.awt.Graphics2D; +import java.util.HashMap; +import java.util.List; +import org.editor.CanvasFrame; +import org.piccode.rt.Context; +import org.piccode.rt.PiccodeException; +import org.piccode.rt.PiccodeNumber; +import org.piccode.rt.PiccodeObject; +import org.piccode.rt.PiccodeReference; +import org.piccode.rt.PiccodeString; +import org.piccode.rt.PiccodeUnit; +import org.piccode.rt.PiccodeValue; +import org.piccode.rt.PiccodeValue.Type; +import org.piccode.rt.modules.NativeFunctionFactory; + +/** + * + * @author hexaredecimal + */ +public class PiccodeBrushedMetalFilterModule { + + public static void addFunctions() { + NativeFunctionFactory.create("brush_metal_new", List.of(), (args, namedArgs, frame) -> { + var bmFilter = new BrushedMetalFilter(); + return new PiccodeReference(bmFilter); + }, null); + + NativeFunctionFactory.create("brush_metal_set_rad", List.of("filter", "rad"), (args, namedArgs, frame) -> { + var _filter = namedArgs.get("filter"); + var rad = namedArgs.get("rad"); + + var ctx = frame == null + ? Context.top + : Context.getContextAt(frame); + var caller = ctx.getTopFrame().caller; + + PiccodeValue.verifyType(caller, _filter, Type.REFERENCE); + PiccodeValue.verifyType(caller, rad, Type.NUMBER); + + var obj = (PiccodeReference) _filter; + var _filter_object = obj.deref(); + if (!(_filter_object instanceof BrushedMetalFilter)) { + throw new PiccodeException(caller.file, caller.line, caller.column, "Filter is not a correct object."); + } + + var filter = (BrushedMetalFilter) _filter_object; + var radius = (int) (double) ((PiccodeNumber) rad).raw(); + + filter.setRadius(radius); + + return new PiccodeReference(_filter_object); + }, null); + + NativeFunctionFactory.create("brush_metal_set_amount", List.of("filter", "amount"), (args, namedArgs, frame) -> { + var _filter = namedArgs.get("filter"); + var amount = namedArgs.get("amount"); + + var ctx = frame == null + ? Context.top + : Context.getContextAt(frame); + var caller = ctx.getTopFrame().caller; + + PiccodeValue.verifyType(caller, _filter, Type.REFERENCE); + PiccodeValue.verifyType(caller, amount, Type.NUMBER); + + var obj = (PiccodeReference) _filter; + var _filter_object = obj.deref(); + if (!(_filter_object instanceof BrushedMetalFilter)) { + throw new PiccodeException(caller.file, caller.line, caller.column, "Filter is not a correct object."); + } + + var filter = (BrushedMetalFilter) _filter_object; + var _amount = (int) (double) ((PiccodeNumber) amount).raw(); + + filter.setRadius(_amount); + + return new PiccodeReference(_filter_object); + }, null); + + NativeFunctionFactory.create("brush_metal_set_shine", List.of("filter", "shine"), (args, namedArgs, frame) -> { + var _filter = namedArgs.get("filter"); + var shine = namedArgs.get("shine"); + + var ctx = frame == null + ? Context.top + : Context.getContextAt(frame); + var caller = ctx.getTopFrame().caller; + + PiccodeValue.verifyType(caller, _filter, Type.REFERENCE); + PiccodeValue.verifyType(caller, shine, Type.NUMBER); + + var obj = (PiccodeReference) _filter; + var _filter_object = obj.deref(); + if (!(_filter_object instanceof BrushedMetalFilter)) { + throw new PiccodeException(caller.file, caller.line, caller.column, "Filter is not a correct object."); + } + + var filter = (BrushedMetalFilter) _filter_object; + var _shine = (int) (double) ((PiccodeNumber) shine).raw(); + + filter.setRadius(_shine); + + return new PiccodeReference(_filter_object); + }, null); + + } + +} diff --git a/src/main/java/org/editor/nativemods/PiccodeFilterModule.java b/src/main/java/org/editor/nativemods/PiccodeFilterModule.java new file mode 100644 index 0000000..278ae3d --- /dev/null +++ b/src/main/java/org/editor/nativemods/PiccodeFilterModule.java @@ -0,0 +1,57 @@ +package org.editor.nativemods; + +import java.awt.image.BufferedImage; +import java.awt.image.BufferedImageOp; +import java.util.List; +import org.piccode.rt.Context; +import org.piccode.rt.PiccodeException; +import org.piccode.rt.PiccodeReference; +import org.piccode.rt.PiccodeValue; +import org.piccode.rt.PiccodeValue.Type; +import org.piccode.rt.modules.NativeFunctionFactory; + +/** + * + * @author hexaredecimal + */ +public class PiccodeFilterModule { + + public static void addFunctions() { + NativeFunctionFactory.create("filter_apply", List.of("filter", "image"), (args, namedArgs, frame) -> { + var _filter = namedArgs.get("filter"); + var image = namedArgs.get("image"); + + var ctx = frame == null + ? Context.top + : Context.getContextAt(frame); + var caller = ctx.getTopFrame().caller; + + PiccodeValue.verifyType(caller, _filter, Type.REFERENCE); + PiccodeValue.verifyType(caller, image, Type.REFERENCE); + + var obj = (PiccodeReference) _filter; + var img = (PiccodeReference) image; + var _filter_object = obj.deref(); + var _buffered_image = img.deref(); + + if (!(_filter_object instanceof BufferedImageOp)) { + throw new PiccodeException(caller.file, caller.line, caller.column, "Filter is not a correct object."); + } + + if (!(_buffered_image instanceof BufferedImage)) { + throw new PiccodeException(caller.file, caller.line, caller.column, "Expected a buffer image. Found " + _buffered_image); + } + + + var filter = (BufferedImageOp) _filter_object; + var _image = (BufferedImage) _buffered_image; + + var result = filter.filter(_image, null); + + return new PiccodeReference(result); + }, null); + + + } + +} diff --git a/src/main/java/org/editor/nativemods/PiccodeImageModule.java b/src/main/java/org/editor/nativemods/PiccodeImageModule.java new file mode 100644 index 0000000..e40654f --- /dev/null +++ b/src/main/java/org/editor/nativemods/PiccodeImageModule.java @@ -0,0 +1,92 @@ +package org.editor.nativemods; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import java.util.HashMap; +import java.util.List; +import org.editor.CanvasFrame; +import org.piccode.rt.Context; +import org.piccode.rt.PiccodeException; +import org.piccode.rt.PiccodeNumber; +import org.piccode.rt.PiccodeObject; +import org.piccode.rt.PiccodeReference; +import org.piccode.rt.PiccodeString; +import org.piccode.rt.PiccodeUnit; +import org.piccode.rt.PiccodeValue; +import org.piccode.rt.PiccodeValue.Type; +import org.piccode.rt.modules.NativeFunctionFactory; + +/** + * + * @author hexaredecimal + */ +public class PiccodeImageModule { + + public static void addFunctions() { + + NativeFunctionFactory.create("image_new", List.of("w", "h"), (args, namedArgs, frame) -> { + var w = namedArgs.get("w"); + var h = namedArgs.get("h"); + + var ctx = frame == null ? + Context.top + : Context.getContextAt(frame); + var caller = ctx.getTopFrame().caller; + + PiccodeValue.verifyType(caller, w, Type.NUMBER); + PiccodeValue.verifyType(caller, h, Type.NUMBER); + + var _w = (int) (double) ((PiccodeNumber) w).raw(); + var _h = (int) (double) ((PiccodeNumber) h).raw(); + + var image = new BufferedImage(_w, _h, BufferedImage.TYPE_INT_ARGB); + return new PiccodeReference(image); + }, null); + + NativeFunctionFactory.create("image_new_typed", List.of("w", "h", "type"), (args, namedArgs, frame) -> { + var w = namedArgs.get("w"); + var h = namedArgs.get("h"); + var type = namedArgs.get("type"); + + var ctx = frame == null ? + Context.top + : Context.getContextAt(frame); + var caller = ctx.getTopFrame().caller; + + PiccodeValue.verifyType(caller, w, Type.NUMBER); + PiccodeValue.verifyType(caller, h, Type.NUMBER); + PiccodeValue.verifyType(caller, type, Type.NUMBER); + + var _w = (int) (double) ((PiccodeNumber) w).raw(); + var _h = (int) (double) ((PiccodeNumber) h).raw(); + var _type = (int) (double) ((PiccodeNumber) type).raw(); + + var image = new BufferedImage(_w, _h, _type); + return new PiccodeReference(image); + }, null); + + NativeFunctionFactory.create("image_get_context", List.of("img"), (args, namedArgs, frame) -> { + var img = namedArgs.get("img"); + + var ctx = frame == null ? + Context.top + : Context.getContextAt(frame); + var caller = ctx.getTopFrame().caller; + + PiccodeValue.verifyType(caller, img, Type.REFERENCE); + + var _buffered_image = ((PiccodeReference)img).deref(); + + if (!(_buffered_image instanceof BufferedImage)) { + throw new PiccodeException(caller.file, caller.line, caller.column, "Expected a buffer image. Found " + _buffered_image); + } + + var bufferedmage = (BufferedImage) _buffered_image; + var gfx = bufferedmage.createGraphics(); + return new PiccodeReference(gfx); + }, null); + + } + +} From afbd1f28141e38643f04b8cf9739f0832c99c1fe Mon Sep 17 00:00:00 2001 From: hexaredecimal Date: Sat, 9 Aug 2025 11:39:02 +0200 Subject: [PATCH 20/48] pom.xml: Add JHLabs filters --- pom.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pom.xml b/pom.xml index 0c67325..d66ea4c 100644 --- a/pom.xml +++ b/pom.xml @@ -77,6 +77,12 @@ PiccodeScript main-SNAPSHOT + + + com.github.Glimmr-Lang + JHLabs + main-SNAPSHOT + From f8f72061fa9b10159ac20b8aaa8c0603e84cda93 Mon Sep 17 00:00:00 2001 From: hexaredecimal Date: Sat, 9 Aug 2025 13:57:11 +0200 Subject: [PATCH 21/48] piccode: Adds more functions to the modules --- piccode/context/ctx.pics | 2 +- piccode/filters/filter.pics | 5 ++ piccode/filters/metal/brushMetal.pics | 8 +++ piccode/image/image.pics | 17 +++++ piccode/pen/draw.pics | 3 + .../PiccodeBrushedMetalFilterModule.java | 8 +-- .../editor/nativemods/PiccodeImageModule.java | 56 ++++++++++++++++ .../editor/nativemods/PiccodePenModule.java | 65 +++++++++++++++++++ 8 files changed, 159 insertions(+), 5 deletions(-) create mode 100644 piccode/filters/filter.pics create mode 100644 piccode/filters/metal/brushMetal.pics create mode 100644 piccode/image/image.pics diff --git a/piccode/context/ctx.pics b/piccode/context/ctx.pics index 302b808..72e3ce3 100644 --- a/piccode/context/ctx.pics +++ b/piccode/context/ctx.pics @@ -35,5 +35,5 @@ Context :: module { // // Returns: // - (Unit) Nothing - drop :: (ctx) = pic_nat_gfx_(ctx) + drop :: (ctx) = pic_nat_gfx_drop(ctx) } diff --git a/piccode/filters/filter.pics b/piccode/filters/filter.pics new file mode 100644 index 0000000..244eced --- /dev/null +++ b/piccode/filters/filter.pics @@ -0,0 +1,5 @@ + +Filter :: module { + apply :: (filter, image) = pic_nat_filter_apply(filter, image) +} + diff --git a/piccode/filters/metal/brushMetal.pics b/piccode/filters/metal/brushMetal.pics new file mode 100644 index 0000000..4a846a5 --- /dev/null +++ b/piccode/filters/metal/brushMetal.pics @@ -0,0 +1,8 @@ + + +BrushMetal :: module { + new :: () = pic_nat_brush_metal_new() + radius :: (filter, radius) = pic_nat_brush_metal_set_rad(filter, radius) + amount :: (filter, radius) = pic_nat_brush_metal_set_amount(filter, radius) + shine :: (filter, radius) = pic_nat_brush_metal_set_shine(filter, radius) +} diff --git a/piccode/image/image.pics b/piccode/image/image.pics new file mode 100644 index 0000000..0bd05f5 --- /dev/null +++ b/piccode/image/image.pics @@ -0,0 +1,17 @@ + +Image :: module { + new :: (w, h) = pic_nat_image_new(w, h) + newWithType :: (w, h, type) = pic_nat_image_new_typed(w, h, type) + getContext :: (img) = pic_nat_image_get_context(img) + fromPath :: (path) = pic_nat_image_new_from_path(path) + + resize :: (img, w, h) = pic_nat_image_resize(img, w, h) + + Type :: module { + RGB := 1 + ARGB := 2 + ARGB_PRE := 3 + BGR := 1 + } +} + diff --git a/piccode/pen/draw.pics b/piccode/pen/draw.pics index 7f14334..4e9e1fa 100644 --- a/piccode/pen/draw.pics +++ b/piccode/pen/draw.pics @@ -59,5 +59,8 @@ Pen :: module { // - (Reference) A modified context with the rendered element. drawOval :: (ctx, x, y, w, h) = pic_nat_draw_oval(ctx, x, y, w, h) + drawImage :: (ctx, image, x, y) = pic_nat_draw_image(ctx, image, x, y) + + drawText :: (ctx, text, x, y) = pic_nat_draw_text(ctx, text, x, y) } diff --git a/src/main/java/org/editor/nativemods/PiccodeBrushedMetalFilterModule.java b/src/main/java/org/editor/nativemods/PiccodeBrushedMetalFilterModule.java index f0e0843..5b46f25 100644 --- a/src/main/java/org/editor/nativemods/PiccodeBrushedMetalFilterModule.java +++ b/src/main/java/org/editor/nativemods/PiccodeBrushedMetalFilterModule.java @@ -74,9 +74,9 @@ public static void addFunctions() { } var filter = (BrushedMetalFilter) _filter_object; - var _amount = (int) (double) ((PiccodeNumber) amount).raw(); + var _amount = (float) (double) ((PiccodeNumber) amount).raw(); - filter.setRadius(_amount); + filter.setAmount(_amount); return new PiccodeReference(_filter_object); }, null); @@ -100,9 +100,9 @@ public static void addFunctions() { } var filter = (BrushedMetalFilter) _filter_object; - var _shine = (int) (double) ((PiccodeNumber) shine).raw(); + var _shine = (float) (double) ((PiccodeNumber) shine).raw(); - filter.setRadius(_shine); + filter.setShine(_shine); return new PiccodeReference(_filter_object); }, null); diff --git a/src/main/java/org/editor/nativemods/PiccodeImageModule.java b/src/main/java/org/editor/nativemods/PiccodeImageModule.java index e40654f..3d895ce 100644 --- a/src/main/java/org/editor/nativemods/PiccodeImageModule.java +++ b/src/main/java/org/editor/nativemods/PiccodeImageModule.java @@ -2,10 +2,15 @@ import java.awt.Color; import java.awt.Graphics2D; +import java.awt.Image; import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; import java.util.HashMap; import java.util.List; +import javax.imageio.ImageIO; import org.editor.CanvasFrame; +import org.editor.icons.ImageLoader; import org.piccode.rt.Context; import org.piccode.rt.PiccodeException; import org.piccode.rt.PiccodeNumber; @@ -66,6 +71,57 @@ public static void addFunctions() { return new PiccodeReference(image); }, null); + NativeFunctionFactory.create("image_new_from_path", List.of("path"), (args, namedArgs, frame) -> { + var path = namedArgs.get("path"); + + var ctx = frame == null ? + Context.top + : Context.getContextAt(frame); + var caller = ctx.getTopFrame().caller; + + PiccodeValue.verifyType(caller, path, Type.STRING); + + try { + BufferedImage image = ImageIO.read(new File(path.raw().toString())); + return new PiccodeReference(image); + } catch (IOException ex) { + var def = (BufferedImage) ImageLoader.getImage(-1); + return new PiccodeReference(def); + } + }, null); + + NativeFunctionFactory.create("image_resize", List.of("img" ,"w", "h"), (args, namedArgs, frame) -> { + var img = namedArgs.get("img"); + var w = namedArgs.get("w"); + var h = namedArgs.get("h"); + + var ctx = frame == null ? + Context.top + : Context.getContextAt(frame); + var caller = ctx.getTopFrame().caller; + + PiccodeValue.verifyType(caller, img, Type.REFERENCE); + PiccodeValue.verifyType(caller, w, Type.NUMBER); + PiccodeValue.verifyType(caller, h, Type.NUMBER); + + var _buffered_image = ((PiccodeReference)img).deref(); + + if (!(_buffered_image instanceof BufferedImage)) { + throw new PiccodeException(caller.file, caller.line, caller.column, "Expected a buffer image. Found " + _buffered_image); + } + + var bufferedmage = (BufferedImage) _buffered_image; + + var _w = (int) (double) ((PiccodeNumber) w).raw(); + var _h = (int) (double) ((PiccodeNumber) h).raw(); + + Image resultingImage = bufferedmage.getScaledInstance(_w, _h, Image.SCALE_DEFAULT); + BufferedImage outputImage = new BufferedImage(_w, _h, BufferedImage.TYPE_INT_RGB); + outputImage.getGraphics().drawImage(resultingImage, 0, 0, null); + + return new PiccodeReference(outputImage); + }, null); + NativeFunctionFactory.create("image_get_context", List.of("img"), (args, namedArgs, frame) -> { var img = namedArgs.get("img"); diff --git a/src/main/java/org/editor/nativemods/PiccodePenModule.java b/src/main/java/org/editor/nativemods/PiccodePenModule.java index 11107c0..7c91b5e 100644 --- a/src/main/java/org/editor/nativemods/PiccodePenModule.java +++ b/src/main/java/org/editor/nativemods/PiccodePenModule.java @@ -2,6 +2,7 @@ import java.awt.Color; import java.awt.Graphics2D; +import java.awt.image.BufferedImage; import java.util.HashMap; import java.util.List; import org.editor.CanvasFrame; @@ -165,6 +166,70 @@ public static void addFunctions() { gfx.drawOval(_x, _y, _w, _h); return obj; }, null); + + NativeFunctionFactory.create("draw_image", List.of("ctx", "img", "x", "y"), (args, namedArgs, frame) -> { + var _ctx = namedArgs.get("ctx"); + var _img = namedArgs.get("img"); + var x = namedArgs.get("x"); + var y = namedArgs.get("y"); + + var ctx = frame == null ? + Context.top + : Context.getContextAt(frame); + var caller = ctx.getTopFrame().caller; + + PiccodeValue.verifyType(caller, _ctx, Type.REFERENCE); + PiccodeValue.verifyType(caller, _img, Type.REFERENCE); + PiccodeValue.verifyType(caller, x, Type.NUMBER); + PiccodeValue.verifyType(caller, y, Type.NUMBER); + + var obj = (PiccodeReference) _ctx; + var imgObj = (PiccodeReference) _img; + var _gfx = obj.deref(); + var _image = imgObj.deref(); + if (!(_gfx instanceof Graphics2D)) { + throw new PiccodeException(caller.file, caller.line, caller.column, "Context is not a correct object. Expected Graphics2D"); + } + if (!(_image instanceof BufferedImage)) { + throw new PiccodeException(caller.file, caller.line, caller.column, "Image in not a correct object. Expected a BufferedImage but found" + _image); + } + + var gfx = (Graphics2D) _gfx; + var img = (BufferedImage) _image; + var _x = (int) (double) ((PiccodeNumber) x).raw(); + var _y = (int) (double) ((PiccodeNumber) y).raw(); + + gfx.drawImage(img, _x, _y, null); + return obj; + }, null); + NativeFunctionFactory.create("draw_text", List.of("ctx", "text", "x", "y"), (args, namedArgs, frame) -> { + var _ctx = namedArgs.get("ctx"); + var _text = namedArgs.get("text"); + var x = namedArgs.get("x"); + var y = namedArgs.get("y"); + + var ctx = frame == null ? + Context.top + : Context.getContextAt(frame); + var caller = ctx.getTopFrame().caller; + + PiccodeValue.verifyType(caller, _ctx, Type.REFERENCE); + PiccodeValue.verifyType(caller, _text, Type.STRING); + PiccodeValue.verifyType(caller, x, Type.NUMBER); + PiccodeValue.verifyType(caller, y, Type.NUMBER); + + var obj = (PiccodeReference) _ctx; + var _gfx = obj.deref(); + if (!(_gfx instanceof Graphics2D)) { + throw new PiccodeException(caller.file, caller.line, caller.column, "Context is not a correct object. Expected Graphics2D"); + } + var gfx = (Graphics2D) _gfx; + var _x = (int) (double) ((PiccodeNumber) x).raw(); + var _y = (int) (double) ((PiccodeNumber) y).raw(); + + gfx.drawString(_text.toString(), _x, _y); + return obj; + }, null); } } From f7bf58deacabc85cf36901c976e6a71d712f1046 Mon Sep 17 00:00:00 2001 From: hexaredecimal Date: Sat, 9 Aug 2025 13:57:48 +0200 Subject: [PATCH 22/48] events: Clear the output window on each compile --- src/main/java/org/editor/events/AccessEvents.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/editor/events/AccessEvents.java b/src/main/java/org/editor/events/AccessEvents.java index 41503e0..2a2e46d 100644 --- a/src/main/java/org/editor/events/AccessEvents.java +++ b/src/main/java/org/editor/events/AccessEvents.java @@ -29,8 +29,9 @@ public static void compileAndRender(ActionEvent e) { var file = ed.file.toString(); var code = ed.textArea.getText(); - CanvasFrame.the().compile(() -> Compiler.compile(file, code)); + AccessFrame.msgs.setText(""); AccessFrame.writeSuccess("Compilation started: "); + CanvasFrame.the().compile(() -> Compiler.compile(file, code)); } public static void compile(ActionEvent e) { From 1aa9059f14e1f2bbc802085743cf878a0a0bcc9c Mon Sep 17 00:00:00 2001 From: hexaredecimal Date: Sat, 9 Aug 2025 13:58:20 +0200 Subject: [PATCH 23/48] Piccode: Register the new modules --- src/main/java/org/piccode/piccode/Piccode.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/org/piccode/piccode/Piccode.java b/src/main/java/org/piccode/piccode/Piccode.java index ba34188..3b03ee6 100644 --- a/src/main/java/org/piccode/piccode/Piccode.java +++ b/src/main/java/org/piccode/piccode/Piccode.java @@ -2,7 +2,10 @@ import org.editor.AccessFrame; import org.editor.EditorWindow; +import org.editor.nativemods.PiccodeBrushedMetalFilterModule; +import org.editor.nativemods.PiccodeFilterModule; import org.editor.nativemods.PiccodeGfxModule; +import org.editor.nativemods.PiccodeImageModule; import org.editor.nativemods.PiccodePenModule; import org.piccode.backend.Compiler; import org.piccode.piccodescript.ErrorAsciiKind; @@ -24,5 +27,8 @@ public static void main(String[] args) { private static void initializeNativeAppModules() { Compiler.addNativeFunctions(PiccodeGfxModule::addFunctions); Compiler.addNativeFunctions(PiccodePenModule::addFunctions); + Compiler.addNativeFunctions(PiccodeBrushedMetalFilterModule::addFunctions); + Compiler.addNativeFunctions(PiccodeFilterModule::addFunctions); + Compiler.addNativeFunctions(PiccodeImageModule::addFunctions); } } From 742a79f5d3bb8e8541547c46fc8e9e16ca70ca78 Mon Sep 17 00:00:00 2001 From: Mfanakagama <51314855+hexaredecimal@users.noreply.github.com> Date: Sat, 9 Aug 2025 14:21:31 +0200 Subject: [PATCH 24/48] Update piccode/image/image.pics Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- piccode/image/image.pics | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/piccode/image/image.pics b/piccode/image/image.pics index 0bd05f5..a3dd5cf 100644 --- a/piccode/image/image.pics +++ b/piccode/image/image.pics @@ -8,10 +8,10 @@ Image :: module { resize :: (img, w, h) = pic_nat_image_resize(img, w, h) Type :: module { - RGB := 1 + RGB := 1 ARGB := 2 ARGB_PRE := 3 - BGR := 1 + BGR := 4 } } From c5fb739602b1399d2db7b37277438e40b9923d22 Mon Sep 17 00:00:00 2001 From: hexaredecimal Date: Tue, 12 Aug 2025 14:44:39 +0200 Subject: [PATCH 25/48] .gitignore: Ignore jar files too --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 6df9964..a10ca8d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ target/ .mvn mvnw* -docs/.obsidian \ No newline at end of file +docs/.obsidian +*.jar From 4aa99b9d7c06786ed006bed392b3053a3a87ae07 Mon Sep 17 00:00:00 2001 From: hexaredecimal Date: Tue, 12 Aug 2025 14:45:24 +0200 Subject: [PATCH 26/48] theme: A subscriber API for thmeming compoments --- .../java/org/editor/theme/ThemeManager.java | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 src/main/java/org/editor/theme/ThemeManager.java diff --git a/src/main/java/org/editor/theme/ThemeManager.java b/src/main/java/org/editor/theme/ThemeManager.java new file mode 100644 index 0000000..a20ecbd --- /dev/null +++ b/src/main/java/org/editor/theme/ThemeManager.java @@ -0,0 +1,64 @@ +package org.editor.theme; + +import com.formdev.flatlaf.FlatDarkLaf; +import com.formdev.flatlaf.FlatLightLaf; +import com.piccode.piccodeplugin.PiccodePluginInterface; +import java.awt.Color; +import java.util.ArrayList; +import java.util.List; +import javax.swing.UIManager; +import org.editor.CodeEditor; + +/** + * + * @author hexaredecimal + */ +public class ThemeManager { + + private static List editors = new ArrayList(); + private static List plugins = new ArrayList(); + public static Color RENDER_BG = Color.WHITE; + public static Color RENDER_FG = Color.BLACK; + public static Color RENDER_TXT2 = Color.BLUE; + public static Color RENDER_GRID = Color.GRAY; + + public static void registerEditor(CodeEditor editor) { + editors.add(editor); + } + + public static void registerPlugin(PiccodePluginInterface plugin) { + plugins.add(plugin); + } + + public static void updateThemes(boolean dark) { + editors.forEach(editor -> editor.setThemeMode(dark)); + plugins.forEach(plugin -> plugin.setThemeMode(dark)); + setFlatLaf(dark); + + if (dark) { + RENDER_BG = new Color(18, 18, 18); + RENDER_FG = Color.WHITE; + RENDER_TXT2 = Color.GREEN; + RENDER_GRID = new Color(18 * 5, 18 * 5, 18 * 5); + } else { + RENDER_BG = Color.WHITE; + RENDER_FG = Color.BLACK; + RENDER_TXT2 = Color.BLUE; + RENDER_GRID = new Color(230, 230, 230); + } + } + + public static void setFlatLaf(boolean dark) { + try { + if (dark) { + FlatDarkLaf.setup(); + FlatDarkLaf.updateUI(); + } else { + FlatLightLaf.setup(); + FlatLightLaf.updateUI(); + } + } catch (Exception ex) { + System.err.println("Failed to initialize LaF"); + } + } +} From 91690feb971b4c22175f07178b4dd6c6140781da Mon Sep 17 00:00:00 2001 From: hexaredecimal Date: Wed, 13 Aug 2025 11:44:51 +0200 Subject: [PATCH 27/48] editor: Somehow I lost the code for switching theme on the code editor --- src/main/java/org/editor/CodeEditor.java | 12 ++++++++++++ src/main/java/org/editor/EditorWindow.java | 19 ++++++++++++++----- .../java/org/editor/theme/ThemeManager.java | 4 ++++ 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/editor/CodeEditor.java b/src/main/java/org/editor/CodeEditor.java index d55e319..e37cdc7 100644 --- a/src/main/java/org/editor/CodeEditor.java +++ b/src/main/java/org/editor/CodeEditor.java @@ -30,6 +30,7 @@ import org.fife.ui.rsyntaxtextarea.RSyntaxTextAreaHighlighter; import org.fife.ui.rsyntaxtextarea.SyntaxConstants; import org.fife.ui.rsyntaxtextarea.TextEditorPane; +import org.fife.ui.rsyntaxtextarea.Theme; import org.fife.ui.rsyntaxtextarea.TokenMakerFactory; import org.fife.ui.rsyntaxtextarea.templates.CodeTemplate; import org.fife.ui.rsyntaxtextarea.templates.StaticCodeTemplate; @@ -297,4 +298,15 @@ public DockKey getDockKey() { public Component getComponent() { return this; } + + public void setThemeMode(boolean dark) { + var themeName = dark ? "monokai" : "vs"; + try { + Theme theme = Theme.load(getClass().getResourceAsStream( + "/org/fife/ui/rsyntaxtextarea/themes/" + themeName +".xml")); + theme.apply(textArea); + } catch (IOException ioe) { // Never happens + ioe.printStackTrace(); + } + } } diff --git a/src/main/java/org/editor/EditorWindow.java b/src/main/java/org/editor/EditorWindow.java index be507e1..30c0efe 100644 --- a/src/main/java/org/editor/EditorWindow.java +++ b/src/main/java/org/editor/EditorWindow.java @@ -43,6 +43,7 @@ import org.editor.panels.FileTreePanel; import org.editor.panels.PluginsPanel; import org.editor.panels.VCPanel; +import org.editor.theme.ThemeManager; import org.fife.rsta.ui.CollapsibleSectionPanel; //import org.fife.rsta.ui.DocumentMap; @@ -74,6 +75,7 @@ public final class EditorWindow extends JFrame implements SearchListener { public static ReplaceDialog replaceDialog; private DockingDesktop desk = new DockingDesktop(); private static CodeEditor selected = null; + private static boolean dark = true; public static EditorWindow the() { if (win == null) { @@ -118,7 +120,7 @@ public EditorWindow() { if (current.getDockable() instanceof CodeEditor ed) { if (event.getFutureState().isClosed()) { - if (removeIfDirty(ed.tabIndex, ed) == false) { + if (removeIfNotDirty(ed.tabIndex, ed) == false) { event.cancel(); } } @@ -229,6 +231,8 @@ public EditorWindow() { win = this; + ThemeManager.updateThemes(dark); + this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setSize(width, height); this.setLocationRelativeTo(null); @@ -251,6 +255,8 @@ public static void addTab(ActionEvent e) { editor.requestFocusInWindow(); current_file.setText(file != null ? file.toString() : "[NONE]"); tabEditors.put(index, editor); + ThemeManager.registerEditor(editor); + ThemeManager.updateThemes(dark); // Add first editor normally if (index == 0) { @@ -271,6 +277,8 @@ public static void addTab(Path path, Void e) { editor.requestFocusInWindow(); tabEditors.put(index, editor); + ThemeManager.registerEditor(editor); + ThemeManager.updateThemes(dark); // Add first editor normally if (index == 0) { win.getContentPane().add(editor); @@ -339,7 +347,7 @@ private static Component makeTabHeader(JTabbedPane tabs, String title) { int index = tabs.indexOfTabComponent(tabHeader); if (index != -1) { var ed = tabEditors.get(index); - removeIfDirty(index, ed); + removeIfNotDirty(index, ed); } }); @@ -364,13 +372,13 @@ public static void removeTab() { return; } - removeIfDirty(index, focused); + removeIfNotDirty(index, focused); } public static void removeAllTabs() { var editors = new HashMap<>(tabEditors); // Copy to avoid ConcurrentModificationException for (var entry : editors.entrySet()) { - removeIfDirty(entry.getKey(), entry.getValue()); + removeIfNotDirty(entry.getKey(), entry.getValue()); } } @@ -378,7 +386,7 @@ public static int tabsCount() { return tabEditors.size(); } - private static boolean removeIfDirty(Integer index, CodeEditor ed) { + private static boolean removeIfNotDirty(Integer index, CodeEditor ed) { if (ed.textArea.isDirty()) { int result = JOptionPane.showConfirmDialog(win, "File " + ed.filePathTruncated() + " is modified. Save?"); if (result == JOptionPane.OK_OPTION) { @@ -387,6 +395,7 @@ private static boolean removeIfDirty(Integer index, CodeEditor ed) { } win.desk.remove((Dockable) ed); // Actual removal from docking layout tabEditors.remove(index); + ThemeManager.removeEditor(ed); migrateIndexes(); return true; diff --git a/src/main/java/org/editor/theme/ThemeManager.java b/src/main/java/org/editor/theme/ThemeManager.java index a20ecbd..47473aa 100644 --- a/src/main/java/org/editor/theme/ThemeManager.java +++ b/src/main/java/org/editor/theme/ThemeManager.java @@ -25,6 +25,10 @@ public class ThemeManager { public static void registerEditor(CodeEditor editor) { editors.add(editor); } + + public static void removeEditor(CodeEditor editor) { + editors.remove(editor); + } public static void registerPlugin(PiccodePluginInterface plugin) { plugins.add(plugin); From de70d0095bc500a0cb002d107c9ec69a12fba8ff Mon Sep 17 00:00:00 2001 From: hexaredecimal Date: Wed, 13 Aug 2025 11:45:26 +0200 Subject: [PATCH 28/48] CanvasFrame: I also lost code for setting colors on the canvas panel --- src/main/java/org/editor/CanvasFrame.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/editor/CanvasFrame.java b/src/main/java/org/editor/CanvasFrame.java index 594f720..a4a3886 100644 --- a/src/main/java/org/editor/CanvasFrame.java +++ b/src/main/java/org/editor/CanvasFrame.java @@ -27,6 +27,7 @@ import javax.swing.SwingUtilities; import javax.swing.Timer; import javax.swing.plaf.basic.BasicGraphicsUtils; +import org.editor.theme.ThemeManager; import org.piccode.ast.Ast; import org.piccode.backend.Compiler; import org.piccode.rt.Context; @@ -254,12 +255,12 @@ private void drawGrid() { gridImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); Graphics2D g2 = gridImage.createGraphics(); // Fill background - g2.setColor(Color.WHITE); + g2.setColor(ThemeManager.RENDER_BG); g2.fillRect(0, 0, getWidth(), getHeight()); if (showGrid) { // Draw grid - g2.setColor(new Color(230, 230, 230)); + g2.setColor(ThemeManager.RENDER_GRID); for (int x = -offsetX % SCALE; x < getWidth(); x += SCALE) { g2.drawLine(x, 0, x, getHeight()); } @@ -270,7 +271,7 @@ private void drawGrid() { if (showRuler) { // Draw axis numbers - g2.setColor(Color.GRAY); + g2.setColor(ThemeManager.RENDER_GRID); for (int x = -offsetX % SCALE; x < getWidth(); x += SCALE) { int value = (x + offsetX) / SCALE; g2.drawString(Integer.toString(value * SCALE), x + 2, 12); @@ -286,7 +287,7 @@ private void drawGrid() { g2.setColor(Color.RED); g2.drawString("y", 8, getHeight() - 5); - g2.setColor(Color.GRAY); + g2.setColor(ThemeManager.RENDER_TXT2); int x = (-offsetX % SCALE + offsetX) / SCALE; int y = (-offsetY % SCALE + offsetY) / SCALE; x *= SCALE; From 5d047c86e1e98dd7d550d0bf1de43011eb91aa29 Mon Sep 17 00:00:00 2001 From: hexaredecimal Date: Wed, 13 Aug 2025 12:11:28 +0200 Subject: [PATCH 29/48] editor: Re implements more features --- src/main/java/org/editor/EditorWindow.java | 10 +-- .../java/org/editor/panels/PluginsPanel.java | 87 ++++++++++++++++++- .../java/org/editor/theme/ThemeManager.java | 1 - 3 files changed, 89 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/editor/EditorWindow.java b/src/main/java/org/editor/EditorWindow.java index 30c0efe..b43054c 100644 --- a/src/main/java/org/editor/EditorWindow.java +++ b/src/main/java/org/editor/EditorWindow.java @@ -73,9 +73,9 @@ public final class EditorWindow extends JFrame implements SearchListener { private CollapsibleSectionPanel csp; public static FindDialog findDialog; public static ReplaceDialog replaceDialog; - private DockingDesktop desk = new DockingDesktop(); + public static DockingDesktop desk = new DockingDesktop(); private static CodeEditor selected = null; - private static boolean dark = true; + public static boolean dark = true; public static EditorWindow the() { if (win == null) { @@ -89,17 +89,13 @@ public static EditorWindow the() { public EditorWindow() { super("Piccode - DashBoard"); + ThemeManager.setFlatLaf(dark); DockingUISettings.getInstance().installUI(); customizeDock(); UIManager.put("Tree.collapsedIcon", UIManager.getIcon("Tree.collapsedIcon")); UIManager.put("Tree.expandedIcon", UIManager.getIcon("Tree.expandedIcon")); - try { - UIManager.setLookAndFeel(new FlatLightLaf()); - } catch (Exception ex) { - System.err.println("Failed to initialize LaF"); - } new CodeEditor(); root = getRootPane(); diff --git a/src/main/java/org/editor/panels/PluginsPanel.java b/src/main/java/org/editor/panels/PluginsPanel.java index 0013be2..3a38918 100644 --- a/src/main/java/org/editor/panels/PluginsPanel.java +++ b/src/main/java/org/editor/panels/PluginsPanel.java @@ -1,6 +1,18 @@ package org.editor.panels; +import com.piccode.piccodeplugin.PiccodePluginPanel; import java.awt.BorderLayout; +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.jar.JarFile; +import org.editor.EditorWindow; +import org.editor.theme.ThemeManager; /** * @@ -8,10 +20,83 @@ */ public class PluginsPanel extends DockablePanel { + private final HashMap loaders = new HashMap<>(); public PluginsPanel() { super(new BorderLayout(), "Plugins", "Plugins", "Browse community plugins", "plugin"); - // TODO: Implement the code + loadPlugins(); + } + + private void loadPlugins() { + var pluginsDir = Paths.get("./etc/plugins/"); + try { + Class baseClass = Class.forName("com.piccode.piccodeplugin.PiccodePluginPanel"); + Files.walk(pluginsDir) + .filter(p -> p.toString().endsWith(".jar")) + .forEach(jarPath -> { + try { + scanJar(jarPath.toFile(), baseClass); + } catch (Exception e) { + e.printStackTrace(); + } + }); + } catch (IOException | ClassNotFoundException ex) { + System.out.println(ex.getMessage()); + } + } + + private void loadPlugin(Class clazz) { + System.out.println("Loading plugin: " + clazz.getName()); + try { + var instance = (PiccodePluginPanel) clazz.getDeclaredConstructor().newInstance(); + instance.init(); + instance = instance.getMainPanel(); + var name = instance.getPluginName(); + var title = "Plugin: " + name; + var dockable = new DockablePanel(new BorderLayout(), name, title, instance.getDescription(), "plugin"); + dockable.add(instance, BorderLayout.CENTER); + ThemeManager.registerPlugin(instance); + var desk = EditorWindow.desk; + desk.addDockable(dockable); + desk.setAutoHide(dockable, true); + ThemeManager.updateThemes(EditorWindow.dark); + + } catch (Exception ex) { + System.out.println("" + ex.getMessage()); + } + } + + private void scanJar(File jarFile, Class baseClass) throws IOException { + URL[] urls = {jarFile.toURI().toURL()}; + // Use system classloader as parent to share core and app classes + URLClassLoader cl = new URLClassLoader(urls, ClassLoader.getSystemClassLoader()); + loaders.put(jarFile, cl); // keep the loader alive + + try (JarFile jar = new JarFile(jarFile)) { + jar.stream() + .filter(e -> e.getName().endsWith(".class") + && !e.getName().equals("module-info.class") + && !e.getName().contains("$") + && !e.getName().contains("META-INF/") + && !e.getName().endsWith("package-info.class")) + .forEach(e -> { + String className = e.getName().replace('/', '.').replaceAll("\\.class$", ""); + try { + // Try loading from app classloader first (fallback pattern) + Class clazz; + try { + clazz = Class.forName(className); + } catch (ClassNotFoundException ex) { + clazz = cl.loadClass(className); + } + if (baseClass.isAssignableFrom(clazz) && !clazz.equals(baseClass)) { + loadPlugin(clazz); + } + } catch (Exception ignore) { + System.out.println("Failed to load class " + className + ": " + ignore.getMessage()); + } + }); + } } } diff --git a/src/main/java/org/editor/theme/ThemeManager.java b/src/main/java/org/editor/theme/ThemeManager.java index 47473aa..d3a6287 100644 --- a/src/main/java/org/editor/theme/ThemeManager.java +++ b/src/main/java/org/editor/theme/ThemeManager.java @@ -6,7 +6,6 @@ import java.awt.Color; import java.util.ArrayList; import java.util.List; -import javax.swing.UIManager; import org.editor.CodeEditor; /** From d433e57267030b5f9ba932b9c6d263e699a466f2 Mon Sep 17 00:00:00 2001 From: hexaredecimal Date: Wed, 13 Aug 2025 12:12:18 +0200 Subject: [PATCH 30/48] pom: Update the pom file --- pom.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pom.xml b/pom.xml index d66ea4c..239d937 100644 --- a/pom.xml +++ b/pom.xml @@ -84,6 +84,12 @@ main-SNAPSHOT + + com.github.Glimmr-Lang + PiccodePlugin + main-SNAPSHOT + + From 741ae3857c8e02b809c8502a95aae57bf073b2e4 Mon Sep 17 00:00:00 2001 From: Mfanakagama <51314855+hexaredecimal@users.noreply.github.com> Date: Fri, 8 Aug 2025 22:46:30 +0200 Subject: [PATCH 31/48] Create dependabot.yml --- .github/dependabot.yml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..356977f --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,7 @@ + +version: 2 +updates: + - package-ecosystem: "" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "weekly" From eef791dd76398d4cb6f2a03c66250c49a3b5b1fb Mon Sep 17 00:00:00 2001 From: Mfanakagama <51314855+hexaredecimal@users.noreply.github.com> Date: Fri, 8 Aug 2025 22:53:40 +0200 Subject: [PATCH 32/48] Update .github/dependabot.yml --- .github/dependabot.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 356977f..b47bf3a 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,7 +1,7 @@ version: 2 updates: - - package-ecosystem: "" # See documentation for possible values + - package-ecosystem: "maven" # See documentation for possible values directory: "/" # Location of package manifests schedule: interval: "weekly" From 6126ada4a0948ead7926311831a83d61723cee65 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Aug 2025 20:58:21 +0000 Subject: [PATCH 33/48] build(deps): bump org.apache.maven.plugins:maven-jar-plugin Bumps [org.apache.maven.plugins:maven-jar-plugin](https://github.com/apache/maven-jar-plugin) from 3.2.0 to 3.4.2. - [Release notes](https://github.com/apache/maven-jar-plugin/releases) - [Commits](https://github.com/apache/maven-jar-plugin/compare/maven-jar-plugin-3.2.0...maven-jar-plugin-3.4.2) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-jar-plugin dependency-version: 3.4.2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 239d937..dd8d507 100644 --- a/pom.xml +++ b/pom.xml @@ -112,7 +112,7 @@ org.apache.maven.plugins maven-jar-plugin - 3.2.0 + 3.4.2 From 94d2c3386c95ae41c87c3fcbc395f9fdd417a896 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Aug 2025 20:58:18 +0000 Subject: [PATCH 34/48] build(deps): bump org.apache.maven.plugins:maven-enforcer-plugin Bumps [org.apache.maven.plugins:maven-enforcer-plugin](https://github.com/apache/maven-enforcer) from 3.5.0 to 3.6.1. - [Release notes](https://github.com/apache/maven-enforcer/releases) - [Commits](https://github.com/apache/maven-enforcer/compare/enforcer-3.5.0...enforcer-3.6.1) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-enforcer-plugin dependency-version: 3.6.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index dd8d507..a1b96e9 100644 --- a/pom.xml +++ b/pom.xml @@ -151,7 +151,7 @@ org.apache.maven.plugins maven-enforcer-plugin - 3.5.0 + 3.6.1 enforce-versions From 70efef5c4fc89a9d157eb2f37d71c70a64750c68 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Aug 2025 20:58:14 +0000 Subject: [PATCH 35/48] build(deps): bump org.junit:junit-bom from 5.12.2 to 5.13.4 Bumps [org.junit:junit-bom](https://github.com/junit-team/junit-framework) from 5.12.2 to 5.13.4. - [Release notes](https://github.com/junit-team/junit-framework/releases) - [Commits](https://github.com/junit-team/junit-framework/compare/r5.12.2...r5.13.4) --- updated-dependencies: - dependency-name: org.junit:junit-bom dependency-version: 5.13.4 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a1b96e9..814805d 100644 --- a/pom.xml +++ b/pom.xml @@ -97,7 +97,7 @@ org.junit junit-bom - 5.12.2 + 5.13.4 pom import From e96dfd5805f04251b5b689f0004e6186c6b0c02f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Aug 2025 20:58:09 +0000 Subject: [PATCH 36/48] build(deps): bump org.apache.maven.plugins:maven-assembly-plugin Bumps [org.apache.maven.plugins:maven-assembly-plugin](https://github.com/apache/maven-assembly-plugin) from 2.4.1 to 3.7.1. - [Release notes](https://github.com/apache/maven-assembly-plugin/releases) - [Commits](https://github.com/apache/maven-assembly-plugin/compare/maven-assembly-plugin-2.4.1...maven-assembly-plugin-3.7.1) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-assembly-plugin dependency-version: 3.7.1 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 814805d..1c32ba2 100644 --- a/pom.xml +++ b/pom.xml @@ -125,7 +125,7 @@ org.apache.maven.plugins maven-assembly-plugin - 2.4.1 + 3.7.1 jar-with-dependencies From 96acc34007ff3d0d862365ecb8afc3fa541aecbf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Aug 2025 20:58:03 +0000 Subject: [PATCH 37/48] build(deps): bump org.bidib.jbidib.com.vldocking:vldocking Bumps [org.bidib.jbidib.com.vldocking:vldocking](https://github.com/akuhtz/vldocking) from 3.0.10 to 3.0.11. - [Release notes](https://github.com/akuhtz/vldocking/releases) - [Changelog](https://github.com/akuhtz/vldocking/blob/master/CHANGELOG.md) - [Commits](https://github.com/akuhtz/vldocking/compare/bidib-3.0.10...bidib-3.0.11) --- updated-dependencies: - dependency-name: org.bidib.jbidib.com.vldocking:vldocking dependency-version: 3.0.11 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1c32ba2..72f8cf1 100644 --- a/pom.xml +++ b/pom.xml @@ -63,7 +63,7 @@ org.bidib.jbidib.com.vldocking vldocking - 3.0.10 + 3.0.11 From 361798e42a80c2e07deb9d2753f0c1cefaeec66b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Aug 2025 17:36:17 +0000 Subject: [PATCH 38/48] build(deps): bump org.antlr:antlr4-runtime from 4.9.3 to 4.13.2 Bumps [org.antlr:antlr4-runtime](https://github.com/antlr/antlr4) from 4.9.3 to 4.13.2. - [Release notes](https://github.com/antlr/antlr4/releases) - [Changelog](https://github.com/antlr/antlr4/blob/dev/CHANGES.txt) - [Commits](https://github.com/antlr/antlr4/compare/4.9.3...4.13.2) --- updated-dependencies: - dependency-name: org.antlr:antlr4-runtime dependency-version: 4.13.2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 72f8cf1..f08c821 100644 --- a/pom.xml +++ b/pom.xml @@ -32,7 +32,7 @@ org.antlr antlr4-runtime - 4.9.3 + 4.13.2 From bb50ed86b05636afbf0993f28b734ff298aba31d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Aug 2025 16:33:57 +0000 Subject: [PATCH 39/48] build(deps): bump org.graalvm.buildtools:native-maven-plugin Bumps [org.graalvm.buildtools:native-maven-plugin](https://github.com/graalvm/native-build-tools) from 0.10.0 to 0.11.0. - [Release notes](https://github.com/graalvm/native-build-tools/releases) - [Commits](https://github.com/graalvm/native-build-tools/compare/0.10.0...0.11.0) --- updated-dependencies: - dependency-name: org.graalvm.buildtools:native-maven-plugin dependency-version: 0.11.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f08c821..ba15fbd 100644 --- a/pom.xml +++ b/pom.xml @@ -186,7 +186,7 @@ org.graalvm.buildtools native-maven-plugin - 0.10.0 + 0.11.0 true From 1651a50d4fd3031523dcb4b58df58b33f3a9edee Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Aug 2025 16:14:20 +0000 Subject: [PATCH 40/48] build(deps): bump com.formdev:flatlaf from 3.6 to 3.6.1 Bumps [com.formdev:flatlaf](https://github.com/JFormDesigner/FlatLaf) from 3.6 to 3.6.1. - [Release notes](https://github.com/JFormDesigner/FlatLaf/releases) - [Changelog](https://github.com/JFormDesigner/FlatLaf/blob/main/CHANGELOG.md) - [Commits](https://github.com/JFormDesigner/FlatLaf/compare/3.6...3.6.1) --- updated-dependencies: - dependency-name: com.formdev:flatlaf dependency-version: 3.6.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ba15fbd..45fbed0 100644 --- a/pom.xml +++ b/pom.xml @@ -39,7 +39,7 @@ com.formdev flatlaf - 3.6 + 3.6.1 From 9334fb1973258fc913aab2f376529fd22deb9dd0 Mon Sep 17 00:00:00 2001 From: hexaredecimal Date: Wed, 13 Aug 2025 12:15:52 +0200 Subject: [PATCH 41/48] editor: Add a bunch of dialogs --- .../editor/dialogs/EditorSettingsDialog.form | 224 ++++++++++++++++++ .../editor/dialogs/EditorSettingsDialog.java | 181 ++++++++++++++ .../editor/dialogs/GeneralSettingsDialog.form | 197 +++++++++++++++ .../editor/dialogs/GeneralSettingsDialog.java | 166 +++++++++++++ .../org/editor/dialogs/SettingsDialog.form | 79 ++++++ .../org/editor/dialogs/SettingsDialog.java | 82 +++++++ 6 files changed, 929 insertions(+) create mode 100644 src/main/java/org/editor/dialogs/EditorSettingsDialog.form create mode 100644 src/main/java/org/editor/dialogs/EditorSettingsDialog.java create mode 100644 src/main/java/org/editor/dialogs/GeneralSettingsDialog.form create mode 100644 src/main/java/org/editor/dialogs/GeneralSettingsDialog.java create mode 100644 src/main/java/org/editor/dialogs/SettingsDialog.form create mode 100644 src/main/java/org/editor/dialogs/SettingsDialog.java diff --git a/src/main/java/org/editor/dialogs/EditorSettingsDialog.form b/src/main/java/org/editor/dialogs/EditorSettingsDialog.form new file mode 100644 index 0000000..c619847 --- /dev/null +++ b/src/main/java/org/editor/dialogs/EditorSettingsDialog.form @@ -0,0 +1,224 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/org/editor/dialogs/EditorSettingsDialog.java b/src/main/java/org/editor/dialogs/EditorSettingsDialog.java new file mode 100644 index 0000000..1e4098a --- /dev/null +++ b/src/main/java/org/editor/dialogs/EditorSettingsDialog.java @@ -0,0 +1,181 @@ +/* + * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license + * Click nbfs://nbhost/SystemFileSystem/Templates/GUIForms/JPanel.java to edit this template + */ +package org.editor.dialogs; + +/** + * + * @author hexaredecimal + */ +public class EditorSettingsDialog extends javax.swing.JPanel { + + /** + * Creates new form EditorSettingsDialog + */ + public EditorSettingsDialog() { + initComponents(); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + jPanel1 = new javax.swing.JPanel(); + jLabel1 = new javax.swing.JLabel(); + jTextField1 = new javax.swing.JTextField(); + jButton1 = new javax.swing.JButton(); + jLabel2 = new javax.swing.JLabel(); + jSpinner1 = new javax.swing.JSpinner(); + jPanel2 = new javax.swing.JPanel(); + jCheckBox1 = new javax.swing.JCheckBox(); + jCheckBox2 = new javax.swing.JCheckBox(); + jCheckBox3 = new javax.swing.JCheckBox(); + jPanel3 = new javax.swing.JPanel(); + jLabel3 = new javax.swing.JLabel(); + jComboBox1 = new javax.swing.JComboBox<>(); + + jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder("Font")); + + jLabel1.setText("Font"); + + jButton1.setText("Pick Font"); + + jLabel2.setText("Font Size"); + + javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); + jPanel1.setLayout(jPanel1Layout); + jPanel1Layout.setHorizontalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addComponent(jLabel2, javax.swing.GroupLayout.DEFAULT_SIZE, 92, Short.MAX_VALUE) + .addComponent(jLabel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, 226, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jButton1) + .addGap(0, 0, Short.MAX_VALUE)) + .addComponent(jSpinner1)) + .addContainerGap()) + ); + jPanel1Layout.setVerticalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabel1) + .addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jButton1)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabel2) + .addComponent(jSpinner1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + jPanel2.setBorder(javax.swing.BorderFactory.createTitledBorder("General")); + + jCheckBox1.setText("Show Line Numbers"); + + jCheckBox2.setText("Enable Syntax Highlighter"); + + jCheckBox3.setText("Enable BookMarks"); + + javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2); + jPanel2.setLayout(jPanel2Layout); + jPanel2Layout.setHorizontalGroup( + jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel2Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jCheckBox2) + .addComponent(jCheckBox1) + .addComponent(jCheckBox3)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + jPanel2Layout.setVerticalGroup( + jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel2Layout.createSequentialGroup() + .addComponent(jCheckBox2) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jCheckBox1) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jCheckBox3) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + jPanel3.setBorder(javax.swing.BorderFactory.createTitledBorder("LookAndFeel")); + + jLabel3.setText("Dark/Light Mode"); + + jComboBox1.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "Dark Mode", "Light Mode" })); + + javax.swing.GroupLayout jPanel3Layout = new javax.swing.GroupLayout(jPanel3); + jPanel3.setLayout(jPanel3Layout); + jPanel3Layout.setHorizontalGroup( + jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel3Layout.createSequentialGroup() + .addContainerGap() + .addComponent(jLabel3, javax.swing.GroupLayout.PREFERRED_SIZE, 157, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(18, 18, 18) + .addComponent(jComboBox1, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addContainerGap()) + ); + jPanel3Layout.setVerticalGroup( + jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel3Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(jComboBox1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jLabel3)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addComponent(jPanel3, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + ); + }// //GEN-END:initComponents + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton jButton1; + private javax.swing.JCheckBox jCheckBox1; + private javax.swing.JCheckBox jCheckBox2; + private javax.swing.JCheckBox jCheckBox3; + private javax.swing.JComboBox jComboBox1; + private javax.swing.JLabel jLabel1; + private javax.swing.JLabel jLabel2; + private javax.swing.JLabel jLabel3; + private javax.swing.JPanel jPanel1; + private javax.swing.JPanel jPanel2; + private javax.swing.JPanel jPanel3; + private javax.swing.JSpinner jSpinner1; + private javax.swing.JTextField jTextField1; + // End of variables declaration//GEN-END:variables +} diff --git a/src/main/java/org/editor/dialogs/GeneralSettingsDialog.form b/src/main/java/org/editor/dialogs/GeneralSettingsDialog.form new file mode 100644 index 0000000..b450678 --- /dev/null +++ b/src/main/java/org/editor/dialogs/GeneralSettingsDialog.form @@ -0,0 +1,197 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/org/editor/dialogs/GeneralSettingsDialog.java b/src/main/java/org/editor/dialogs/GeneralSettingsDialog.java new file mode 100644 index 0000000..2883926 --- /dev/null +++ b/src/main/java/org/editor/dialogs/GeneralSettingsDialog.java @@ -0,0 +1,166 @@ +/* + * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license + * Click nbfs://nbhost/SystemFileSystem/Templates/GUIForms/JPanel.java to edit this template + */ +package org.editor.dialogs; + +/** + * + * @author hexaredecimal + */ +public class GeneralSettingsDialog extends javax.swing.JPanel { + + /** + * Creates new form GeneralSettingsDialog + */ + public GeneralSettingsDialog() { + initComponents(); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + jPanel1 = new javax.swing.JPanel(); + jLabel1 = new javax.swing.JLabel(); + jTextField1 = new javax.swing.JTextField(); + jLabel2 = new javax.swing.JLabel(); + jTextField2 = new javax.swing.JTextField(); + jButton1 = new javax.swing.JButton(); + jPanel2 = new javax.swing.JPanel(); + jLabel3 = new javax.swing.JLabel(); + jTextField3 = new javax.swing.JTextField(); + jLabel4 = new javax.swing.JLabel(); + jTextField4 = new javax.swing.JTextField(); + jLabel5 = new javax.swing.JLabel(); + + jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder("General")); + + jLabel1.setText("Working Directory"); + + jLabel2.setText("Project Name"); + + jButton1.setLabel("Update"); + + javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); + jPanel1.setLayout(jPanel1Layout); + jPanel1Layout.setHorizontalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 150, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jTextField1)) + .addGroup(jPanel1Layout.createSequentialGroup() + .addComponent(jLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, 150, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jTextField2, javax.swing.GroupLayout.DEFAULT_SIZE, 349, Short.MAX_VALUE)) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() + .addGap(0, 0, Short.MAX_VALUE) + .addComponent(jButton1))) + .addContainerGap()) + ); + jPanel1Layout.setVerticalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabel1) + .addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabel2) + .addComponent(jTextField2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 15, Short.MAX_VALUE) + .addComponent(jButton1) + .addContainerGap()) + ); + + jPanel2.setBorder(javax.swing.BorderFactory.createTitledBorder("Runtime")); + + jLabel3.setText("Entry File"); + + jTextField3.setText("./main.pics"); + + jLabel4.setText("Arguments"); + + jLabel5.setFont(new java.awt.Font("sansserif", 0, 10)); // NOI18N + jLabel5.setForeground(new java.awt.Color(204, 204, 204)); + jLabel5.setText("NOTE: Arguments are separated by a space"); + + javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2); + jPanel2.setLayout(jPanel2Layout); + jPanel2Layout.setHorizontalGroup( + jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel2Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addComponent(jLabel4, javax.swing.GroupLayout.DEFAULT_SIZE, 94, Short.MAX_VALUE) + .addComponent(jLabel3, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jTextField3) + .addComponent(jTextField4, javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(jLabel5, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap()) + ); + jPanel2Layout.setVerticalGroup( + jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel2Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabel3) + .addComponent(jTextField3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabel4) + .addComponent(jTextField4, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel5) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jPanel2, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jPanel1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + ); + }// //GEN-END:initComponents + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton jButton1; + private javax.swing.JLabel jLabel1; + private javax.swing.JLabel jLabel2; + private javax.swing.JLabel jLabel3; + private javax.swing.JLabel jLabel4; + private javax.swing.JLabel jLabel5; + private javax.swing.JPanel jPanel1; + private javax.swing.JPanel jPanel2; + private javax.swing.JTextField jTextField1; + private javax.swing.JTextField jTextField2; + private javax.swing.JTextField jTextField3; + private javax.swing.JTextField jTextField4; + // End of variables declaration//GEN-END:variables +} diff --git a/src/main/java/org/editor/dialogs/SettingsDialog.form b/src/main/java/org/editor/dialogs/SettingsDialog.form new file mode 100644 index 0000000..a459d89 --- /dev/null +++ b/src/main/java/org/editor/dialogs/SettingsDialog.form @@ -0,0 +1,79 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/org/editor/dialogs/SettingsDialog.java b/src/main/java/org/editor/dialogs/SettingsDialog.java new file mode 100644 index 0000000..072d6ec --- /dev/null +++ b/src/main/java/org/editor/dialogs/SettingsDialog.java @@ -0,0 +1,82 @@ +/* + * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license + * Click nbfs://nbhost/SystemFileSystem/Templates/GUIForms/JPanel.java to edit this template + */ +package org.editor.dialogs; + +/** + * + * @author hexaredecimal + */ +public class SettingsDialog extends javax.swing.JPanel { + + /** + * Creates new form SettingsDialog + */ + public SettingsDialog() { + initComponents(); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + jPanel1 = new javax.swing.JPanel(); + jTabbedPane1 = new javax.swing.JTabbedPane(); + jButton1 = new javax.swing.JButton(); + jButton2 = new javax.swing.JButton(); + + javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); + jPanel1.setLayout(jPanel1Layout); + jPanel1Layout.setHorizontalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jTabbedPane1) + ); + jPanel1Layout.setVerticalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addComponent(jTabbedPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 303, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, Short.MAX_VALUE)) + ); + + jButton1.setText("jButton1"); + + jButton2.setText("jButton2"); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap(333, Short.MAX_VALUE) + .addComponent(jButton2) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jButton1) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jButton1) + .addComponent(jButton2)) + .addGap(0, 13, Short.MAX_VALUE)) + ); + }// //GEN-END:initComponents + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton jButton1; + private javax.swing.JButton jButton2; + private javax.swing.JPanel jPanel1; + private javax.swing.JTabbedPane jTabbedPane1; + // End of variables declaration//GEN-END:variables +} From 5428cb7b3cda03e2674f49fce23a6b817ad69e78 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Sep 2025 15:16:07 +0000 Subject: [PATCH 42/48] build(deps): bump org.graalvm.buildtools:native-maven-plugin Bumps [org.graalvm.buildtools:native-maven-plugin](https://github.com/graalvm/native-build-tools) from 0.11.0 to 0.11.1. - [Release notes](https://github.com/graalvm/native-build-tools/releases) - [Commits](https://github.com/graalvm/native-build-tools/compare/0.11.0...0.11.1) --- updated-dependencies: - dependency-name: org.graalvm.buildtools:native-maven-plugin dependency-version: 0.11.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 45fbed0..bd94baa 100644 --- a/pom.xml +++ b/pom.xml @@ -186,7 +186,7 @@ org.graalvm.buildtools native-maven-plugin - 0.11.0 + 0.11.1 true From fe492e0ebaa4950a5e233179565a3f7461225686 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Oct 2025 12:24:48 +0000 Subject: [PATCH 43/48] build(deps): bump org.junit:junit-bom from 5.13.4 to 6.0.0 Bumps [org.junit:junit-bom](https://github.com/junit-team/junit-framework) from 5.13.4 to 6.0.0. - [Release notes](https://github.com/junit-team/junit-framework/releases) - [Commits](https://github.com/junit-team/junit-framework/compare/r5.13.4...r6.0.0) --- updated-dependencies: - dependency-name: org.junit:junit-bom dependency-version: 6.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index bd94baa..a7cc871 100644 --- a/pom.xml +++ b/pom.xml @@ -97,7 +97,7 @@ org.junit junit-bom - 5.13.4 + 6.0.0 pom import From 292ad287d7c7b3329e0e59b788326e304cff03d1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Oct 2025 12:11:21 +0000 Subject: [PATCH 44/48] build(deps): bump org.apache.maven.plugins:maven-enforcer-plugin Bumps [org.apache.maven.plugins:maven-enforcer-plugin](https://github.com/apache/maven-enforcer) from 3.6.1 to 3.6.2. - [Release notes](https://github.com/apache/maven-enforcer/releases) - [Commits](https://github.com/apache/maven-enforcer/compare/enforcer-3.6.1...enforcer-3.6.2) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-enforcer-plugin dependency-version: 3.6.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a7cc871..4b48f2d 100644 --- a/pom.xml +++ b/pom.xml @@ -151,7 +151,7 @@ org.apache.maven.plugins maven-enforcer-plugin - 3.6.1 + 3.6.2 enforce-versions From db567a389f5a695e911b18b3da5fc9a9af3d6594 Mon Sep 17 00:00:00 2001 From: hexaredecimal Date: Fri, 10 Oct 2025 06:42:32 +0200 Subject: [PATCH 45/48] About: Changed the name of the organization --- src/main/java/org/editor/panels/AboutPanel.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/editor/panels/AboutPanel.java b/src/main/java/org/editor/panels/AboutPanel.java index 5da656d..1793f44 100644 --- a/src/main/java/org/editor/panels/AboutPanel.java +++ b/src/main/java/org/editor/panels/AboutPanel.java @@ -38,11 +38,11 @@ private void initComponents() { jLabel1.setName(""); // NOI18N jLabel4.setFont(new java.awt.Font("sansserif", 1, 13)); // NOI18N - jLabel4.setText("Brought to you by Glimmir developers"); + jLabel4.setText("Brought to you by Solaris Studio developers"); jTextPane1.setEditable(false); jTextPane1.setBackground(new java.awt.Color(255, 255, 255)); - jTextPane1.setText("\ndrawString(\"\n+--------------------------------------------+\n | ▄▖▘ ▌ |\n | ▙▌▌▛▘▀▌▛▘▛▘▛▌▛▘▛▌▛▌█▌ |\n | ▌ ▌▙▖█▌▄▌▄▌▙▌▙▖▙▌▙▌▙▖ |\n | Creativity + Logic + Math |\n+---------------------------------------------+\n\", 0, 0)\n\nBrought to you by glimmr developers\n\nLead developer: Gama Sibusiso Vincent\nAI and Plugin intergration: TODO\nDocumenentation: TODO\n\nCreated 100% in java using java swing, antlr4 and flatlaf. \nIcons pack dowloaded from icons8"); + jTextPane1.setText("\nPen::drawText(\"\n+--------------------------------------------+\n | ▄▖▘ ▌ |\n | ▙▌▌▛▘▀▌▛▘▛▘▛▌▛▘▛▌▛▌█▌ |\n | ▌ ▌▙▖█▌▄▌▄▌▙▌▙▖▙▌▙▌▙▖ |\n | Creativity + Logic + Math |\n+---------------------------------------------+\n\", 0, 0)\n\nBrought to you by glimmr developers\n\nLead developer: Gama Sibusiso Vincent\nAI and Plugin intergration: TODO\nDocumenentation: TODO\n\nCreated 100% in java using java swing, antlr4 and flatlaf. \nIcons pack dowloaded from icons8"); jTextPane1.setCursor(new java.awt.Cursor(java.awt.Cursor.TEXT_CURSOR)); jScrollPane1.setViewportView(jTextPane1); From 48e67567f67e305b944f55d49cbbeb0e399407b7 Mon Sep 17 00:00:00 2001 From: INNOCENT-ops806 <240418541@tut4life.ac.za> Date: Wed, 6 Aug 2025 07:14:18 +0200 Subject: [PATCH 46/48] Remove the conflict --- README.md | 65 ------------------------------------------------------- 1 file changed, 65 deletions(-) delete mode 100644 README.md diff --git a/README.md b/README.md deleted file mode 100644 index 314a638..0000000 --- a/README.md +++ /dev/null @@ -1,65 +0,0 @@ -
@@ -15,37 +14,43 @@ [![Java CI with Maven](https://github.com/Glimmr-Lang/PicassoCode/actions/workflows/maven.yml/badge.svg)](https://github.com/Glimmr-Lang/PicassoCode/actions/workflows/maven.yml) ## About + Piccasso code is an image editor that uses code to create/edit an image. This allows powerful designs to be created with ease and -automation. The editor uses *glimr* as the scripting language for writing the image editing code. +automation. The editor uses _glimr_ as the scripting language for writing the image editing code. ## Download ->> Coming soon + +> > Coming soon ## Building ```sh -$ git clone git@github.com:hexaredecimal/Piccode.git -$ cd Piccode -$ mvn package +git clone git@github.com:hexaredecimal/Piccode.git +cd Piccode +mvn package ``` + ### Test your build + ```sh -$ java -jar target/Piccode-1.0-SNAPSHOT-jar-with-dependencies.jar +java -jar target/Piccode-1.0-SNAPSHOT-jar-with-dependencies.jar ``` - ## Inspired by + Piccassocode is heavily inspired by the [OpenSCAD](https://openscad.org/) program and tries to mimic its functionality as much as it can while still being an image editor. I was stoked when I tried OpenSCAD for the first time and ended up -challenging myself to start a new project based araound the idea. A friend suggested something that has to do with graphics -and my first though was OpenSCAD, but 2D. The idea quickly grew and the small program became an image editor. +challenging myself to start a new project based around the idea. A friend suggested something that has to do with graphics +and my first though was OpenSCAD, but 2D. The idea quickly grew and the small program became an image editor. ## References + [java image filters](http://www.jhlabs.com/ip/filters/index.html) [Icons8 Pack](https://icons8.com/icons/parakeet--style-parakeet) ## License + ```sh drawString(" +-----------------------------------+ @@ -56,7 +61,5 @@ drawString(" +-----------------------------------+ ", 0, 0) // Released under the MIT LICENSE ``` ->> Thank you for viewing. - - +> > Thank you for viewing. From 26bd5a7a8556321cea2bc81793b356d5fd3940a3 Mon Sep 17 00:00:00 2001 From: "coderabbitai[bot]" <136622811+coderabbitai[bot]@users.noreply.github.com> Date: Wed, 6 Aug 2025 05:23:31 +0000 Subject: [PATCH 02/48] =?UTF-8?q?=F0=9F=93=9D=20CodeRabbit=20Chat:=20Add?= =?UTF-8?q?=20pytest=20test=20suite=20for=20README=20validation=20with=20s?= =?UTF-8?q?upporting=20files=20and=20docs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pytest.ini | 10 + requirements-test.txt | 4 + run_readme_tests.py | 36 +++ tests/test_readme_validation.py | 427 ++++++++++++++++++++++++++++++++ 4 files changed, 477 insertions(+) create mode 100644 pytest.ini create mode 100644 requirements-test.txt create mode 100644 run_readme_tests.py create mode 100644 tests/test_readme_validation.py diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000..2b397c4 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,10 @@ +[tool:pytest] +testpaths = tests +python_files = test_*.py +python_classes = Test* +python_functions = test_* +addopts = -v --tb=short --strict-markers +markers = + slow: marks tests as slow (deselect with '-m "not slow"') + integration: marks tests as integration tests + unit: marks tests as unit tests \ No newline at end of file diff --git a/requirements-test.txt b/requirements-test.txt new file mode 100644 index 0000000..9e14c88 --- /dev/null +++ b/requirements-test.txt @@ -0,0 +1,4 @@ +pytest>=7.0.0 +pytest-mock>=3.6.1 +requests>=2.25.1 +pathlib2>=2.3.7; python_version < '3.4' \ No newline at end of file diff --git a/run_readme_tests.py b/run_readme_tests.py new file mode 100644 index 0000000..e2d8d2f --- /dev/null +++ b/run_readme_tests.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 +""" +Simple test runner for README validation tests. +Run this script to execute all README-related tests. +""" + +import subprocess +import sys +import os + +def main(): + """Run the README validation tests.""" + try: + # Change to the repository root directory + repo_root = os.path.dirname(os.path.abspath(__file__)) + os.chdir(repo_root) + + # Run pytest with verbose output + result = subprocess.run([ + sys.executable, "-m", "pytest", + "tests/test_readme_validation.py", + "-v", "--tb=short" + ], capture_output=False) + + return result.returncode + + except FileNotFoundError: + print("Error: pytest not found. Please install pytest:") + print("pip install -r requirements-test.txt") + return 1 + except Exception as e: + print(f"Error running tests: {e}") + return 1 + +if __name__ == "__main__": + sys.exit(main()) \ No newline at end of file diff --git a/tests/test_readme_validation.py b/tests/test_readme_validation.py new file mode 100644 index 0000000..d16d2b7 --- /dev/null +++ b/tests/test_readme_validation.py @@ -0,0 +1,427 @@ +import pytest +import re +import requests +from pathlib import Path +from unittest.mock import patch, Mock + + +class TestReadmeValidation: + """Comprehensive test suite for README.md validation and content verification.""" + + @pytest.fixture + def readme_content(self): + """Fixture to load README.md content for testing.""" + readme_path = Path("README.md") + if readme_path.exists(): + return readme_path.read_text(encoding='utf-8') + return "" + + def test_readme_file_exists(self): + """Test that README.md file exists in the repository root.""" + readme_path = Path("README.md") + assert readme_path.exists(), "README.md file should exist in repository root" + assert readme_path.is_file(), "README.md should be a file, not a directory" + + def test_readme_is_not_empty(self, readme_content): + """Test that README.md is not empty and has meaningful content.""" + assert readme_content.strip(), "README.md should not be empty" + assert len(readme_content.strip()) > 100, "README.md should have substantial content" + + def test_project_title_present(self, readme_content): + """Test that the project title 'Piccaso Code' is present in README.""" + assert "Piccaso Code" in readme_content, "Project title 'Piccaso Code' should be present" + # Also test for the correct spelling variant + assert "Piccasso code" in readme_content, "Alternative spelling 'Piccasso code' should be present" + + def test_project_description_present(self, readme_content): + """Test that key project description elements are present.""" + assert "image editor" in readme_content.lower(), "Should mention 'image editor'" + assert "java" in readme_content.lower(), "Should mention 'java' as the programming language" + assert "glimr" in readme_content.lower(), "Should mention 'glimr' scripting language" + assert "code to create/edit an image" in readme_content.lower(), "Should describe core functionality" + + def test_html_table_structure(self, readme_content): + """Test that HTML table structure is valid and well-formed.""" + # Test for table opening and closing tags + assert "" in readme_content, "Should contain opening table tag" + assert "
" in readme_content, "Should contain closing table tag" + + # Test for proper row structure + table_rows = re.findall(r"
.*?
- - - - -
- - -

Piccaso Code

-
Creativity + Logic + Math
-

A code based image editor created 100% in java

-
- -[![Java CI with Maven](https://github.com/Glimmr-Lang/PicassoCode/actions/workflows/maven.yml/badge.svg)](https://github.com/Glimmr-Lang/PicassoCode/actions/workflows/maven.yml) - -## About - -Piccasso code is an image editor that uses code to create/edit an image. This allows powerful designs to be created with ease and -automation. The editor uses _glimr_ as the scripting language for writing the image editing code. - -## Download - -> > Coming soon - -## Building - -```sh -git clone git@github.com:hexaredecimal/Piccode.git -cd Piccode -mvn package -``` - -### Test your build - -```sh -java -jar target/Piccode-1.0-SNAPSHOT-jar-with-dependencies.jar -``` - -## Inspired by - -Piccassocode is heavily inspired by the [OpenSCAD](https://openscad.org/) program and tries to mimic its functionality -as much as it can while still being an image editor. I was stoked when I tried OpenSCAD for the first time and ended up -challenging myself to start a new project based around the idea. A friend suggested something that has to do with graphics -and my first though was OpenSCAD, but 2D. The idea quickly grew and the small program became an image editor. - -## References - -[java image filters](http://www.jhlabs.com/ip/filters/index.html) - -[Icons8 Pack](https://icons8.com/icons/parakeet--style-parakeet) - -## License - -```sh -drawString(" -+-----------------------------------+ -| ▄▖▘ ▌ | -| ▙▌▌▛▘▀▌▛▘▛▘▛▌▛▘▛▌▛▌█▌ | -| ▌ ▌▙▖█▌▄▌▄▌▙▌▙▖▙▌▙▌▙▖ | -| Creativity + Logic + Math | -+-----------------------------------+ -", 0, 0) // Released under the MIT LICENSE -``` - -> > Thank you for viewing. From 96f389d98a10a79567bdc800c6160fd720a78c78 Mon Sep 17 00:00:00 2001 From: hexaredecimal Date: Thu, 7 Aug 2025 11:08:48 +0200 Subject: [PATCH 47/48] README: Fix conflicts in readme --- README.md | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..a7d51a5 --- /dev/null +++ b/README.md @@ -0,0 +1,117 @@ + + + + + +
+ + +

Picasso Code

+
Creativity + Logic + Math
+

A code based image editor created 100% in java

+
+ +[![Java CI with Maven](https://github.com/Glimmr-Lang/PicassoCode/actions/workflows/maven.yml/badge.svg)](https://github.com/Glimmr-Lang/PicassoCode/actions/workflows/maven.yml) + +## About +<<<<<<< HEAD +<<<<<<< HEAD +Picasso code is an image editor that uses code to create/edit an image. This allows powerful designs to be created with ease and +automation. The editor uses *PiccodeScript* as the scripting language for writing the image editing code. +======= + +Piccasso code is an image editor that uses code to create/edit an image. This allows powerful designs to be created with ease and +automation. The editor uses _glimr_ as the scripting language for writing the image editing code. +>>>>>>> 0064ac3 (fix: corrected a spelling error in the readme file) +======= + +Piccasso code is an image editor that uses code to create/edit an image. This allows powerful designs to be created with ease and +automation. The editor uses _glimr_ as the scripting language for writing the image editing code. +======= +Picasso code is an image editor that uses code to create/edit an image. This allows powerful designs to be created with ease and +automation. The editor uses *PiccodeScript* as the scripting language for writing the image editing code. +>>>>>>> 455b066 (README: Fixed mistakes in the README) +>>>>>>> 955b7fb (README: Fixed mistakes in the README) + +## Download + +> > Coming soon + +## Building + +```sh +<<<<<<< HEAD +<<<<<<< HEAD +$ git clone https://github.com/Glimmr-Lang/PicassoCode.git +$ cd PicassoCode +$ mvn package +``` +### Test your build +```sh +$ java -jar target/Piccode-1.0-SNAPSHOT-jar-with-dependencies.jar +======= +git clone git@github.com:hexaredecimal/Piccode.git +cd Piccode +mvn package +>>>>>>> 0064ac3 (fix: corrected a spelling error in the readme file) +======= +git clone git@github.com:hexaredecimal/Piccode.git +cd Piccode +mvn package +======= +$ git clone https://github.com/Glimmr-Lang/PicassoCode.git +$ cd PicassoCode +$ mvn package +``` +### Test your build +```sh +$ java -jar target/Piccode-1.0-SNAPSHOT-jar-with-dependencies.jar +>>>>>>> 455b066 (README: Fixed mistakes in the README) +>>>>>>> 955b7fb (README: Fixed mistakes in the README) +``` + +### Test your build + +```sh +java -jar target/Piccode-1.0-SNAPSHOT-jar-with-dependencies.jar +``` + +## Inspired by +<<<<<<< HEAD +<<<<<<< HEAD +PicassoCode is heavily inspired by the [OpenSCAD](https://openscad.org/) program and tries to mimic its functionality +======= + +Piccassocode is heavily inspired by the [OpenSCAD](https://openscad.org/) program and tries to mimic its functionality +>>>>>>> 0064ac3 (fix: corrected a spelling error in the readme file) +======= + +Piccassocode is heavily inspired by the [OpenSCAD](https://openscad.org/) program and tries to mimic its functionality +======= +PicassoCode is heavily inspired by the [OpenSCAD](https://openscad.org/) program and tries to mimic its functionality +>>>>>>> 455b066 (README: Fixed mistakes in the README) +>>>>>>> 955b7fb (README: Fixed mistakes in the README) +as much as it can while still being an image editor. I was stoked when I tried OpenSCAD for the first time and ended up +challenging myself to start a new project based around the idea. A friend suggested something that has to do with graphics +and my first though was OpenSCAD, but 2D. The idea quickly grew and the small program became an image editor. + +## References + +[java image filters](http://www.jhlabs.com/ip/filters/index.html) + +[Icons8 Pack](https://icons8.com/icons/parakeet--style-parakeet) + +## License + +```sh +Render::drawString(" ++-----------------------------------+ +| ▄▖▘ ▌ | +| ▙▌▌▛▘▀▌▛▘▛▘▛▌▛▘▛▌▛▌█▌ | +| ▌ ▌▙▖█▌▄▌▄▌▙▌▙▖▙▌▙▌▙▖ | +| Creativity + Logic + Math | ++-----------------------------------+ +", 0, 0) // Released under the MIT LICENSE +``` + +> > Thank you for viewing. From f99bbb72a9bbeb08ce36e6f690303ad2b0c81604 Mon Sep 17 00:00:00 2001 From: INNOCENT-ops806 <240418541@tut4life.ac.za> Date: Sat, 15 Nov 2025 15:41:58 +0200 Subject: [PATCH 48/48] feat: Use the system Object to get the current working directory This commit hopefully accomplishes the todo that was made to use the system object to get the current working directory --- .../java/org/editor/events/MenuEvents.java | 225 +++++++++--------- 1 file changed, 112 insertions(+), 113 deletions(-) diff --git a/src/main/java/org/editor/events/MenuEvents.java b/src/main/java/org/editor/events/MenuEvents.java index 3b04f33..50a28b8 100644 --- a/src/main/java/org/editor/events/MenuEvents.java +++ b/src/main/java/org/editor/events/MenuEvents.java @@ -23,118 +23,117 @@ */ public class MenuEvents { - public static void gotoLineEvent(ActionEvent e) { - var findDialog = EditorWindow.findDialog; - var replaceDialog = EditorWindow.replaceDialog; - if (findDialog.isVisible()) { - findDialog.setVisible(false); - } - if (replaceDialog.isVisible()) { - replaceDialog.setVisible(false); - } - GoToDialog dialog = new GoToDialog(EditorWindow.win); - - var ed = EditorWindow.getSelectedEditor(); - if (ed == null) { - return; - } + public static void gotoLineEvent(ActionEvent e) { + var findDialog = EditorWindow.findDialog; + var replaceDialog = EditorWindow.replaceDialog; + if (findDialog.isVisible()) { + findDialog.setVisible(false); + } + if (replaceDialog.isVisible()) { + replaceDialog.setVisible(false); + } + GoToDialog dialog = new GoToDialog(EditorWindow.win); + + var ed = EditorWindow.getSelectedEditor(); + if (ed == null) { + return; + } var textArea = ed.textArea; - dialog.setMaxLineNumberAllowed(textArea.getLineCount()); - dialog.setVisible(true); - int line = dialog.getLineNumber(); - if (line > 0) { - try { - textArea.setCaretPosition(textArea.getLineStartOffset(line - 1)); - } catch (BadLocationException ble) { // Never happens - UIManager.getLookAndFeel().provideErrorFeedback(textArea); - ble.printStackTrace(); - } - } - } - - static void replaceEvent(ActionEvent e) { - var replaceDialog = EditorWindow.replaceDialog; - var findDialog = EditorWindow.findDialog; - if (findDialog.isVisible()) { - findDialog.setVisible(false); - } - replaceDialog.setVisible(true); - } - - static void findEvent(ActionEvent e) { - var replaceDialog = EditorWindow.replaceDialog; - var findDialog = EditorWindow.findDialog; - if (replaceDialog.isVisible()) { - replaceDialog.setVisible(false); - } - findDialog.setVisible(true); - } - - public static void aboutDialog(ActionEvent e) { - new AboutDialog(EditorWindow.win); - } - - public static void closeTab(ActionEvent e) { - EditorWindow.removeTab(); - } - - public static void closeAllTabs(ActionEvent e) { - EditorWindow.removeAllTabs(); - } - - static void openFile(ActionEvent e) { - // TODO: Use the System object to get the current pwd - var fileChooser = new JFileChooser("."); - fileChooser.setFileFilter(FileFilter.mdFilter); - fileChooser.setFileFilter(FileFilter.picsFilter); - - int status = fileChooser.showOpenDialog(EditorWindow.win); - if (status != JFileChooser.APPROVE_OPTION) { - return; - } - - var fp = fileChooser.getSelectedFile(); - var path = fp.toPath(); - EditorWindow.addTab(path, null); - } - - static void saveFile(ActionEvent e) { - if (EditorWindow.tabsCount() == 0) { - return; - } - var ed = EditorWindow.getSelectedEditor(); - if (ed == null) { - return; - } - ed.saveFile(); - } - - static void saveFileAs(ActionEvent e) { - if (EditorWindow.tabsCount() == 1) { - return; - } - var ed = EditorWindow.getSelectedEditor(); - if (ed == null) { - return; - } - ed.saveFileAs(); - } - - static void saveAllFiles(ActionEvent e) { - EditorWindow.saveAll(); - } - - static void closeFile(ActionEvent e) { - closeTab(e); - } - - static void quit(ActionEvent e) { - closeAllTabs(e); - System.exit(0); - } - - static void newFile(ActionEvent e) { - // TODO: Use a file creator dialog in the future - EditorWindow.addTab(e); - } + dialog.setMaxLineNumberAllowed(textArea.getLineCount()); + dialog.setVisible(true); + int line = dialog.getLineNumber(); + if (line > 0) { + try { + textArea.setCaretPosition(textArea.getLineStartOffset(line - 1)); + } catch (BadLocationException ble) { // Never happens + UIManager.getLookAndFeel().provideErrorFeedback(textArea); + ble.printStackTrace(); + } + } + } + + static void replaceEvent(ActionEvent e) { + var replaceDialog = EditorWindow.replaceDialog; + var findDialog = EditorWindow.findDialog; + if (findDialog.isVisible()) { + findDialog.setVisible(false); + } + replaceDialog.setVisible(true); + } + + static void findEvent(ActionEvent e) { + var replaceDialog = EditorWindow.replaceDialog; + var findDialog = EditorWindow.findDialog; + if (replaceDialog.isVisible()) { + replaceDialog.setVisible(false); + } + findDialog.setVisible(true); + } + + public static void aboutDialog(ActionEvent e) { + new AboutDialog(EditorWindow.win); + } + + static void closeTab(ActionEvent e) { + EditorWindow.removeTab(); + } + + public static void closeAllTabs(ActionEvent e) { + EditorWindow.removeAllTabs(); + } + + static void openFile(ActionEvent e) { + var fileChooser = new JFileChooser(System.getProperty("user.dir")); + fileChooser.setFileFilter(FileFilter.mdFilter); + fileChooser.setFileFilter(FileFilter.picsFilter); + + int status = fileChooser.showOpenDialog(EditorWindow.win); + if (status != JFileChooser.APPROVE_OPTION) { + return; + } + + var fp = fileChooser.getSelectedFile(); + var path = fp.toPath(); + EditorWindow.addTab(path, null); + } + + static void saveFile(ActionEvent e) { + if (EditorWindow.tabsCount() == 0) { + return; + } + var ed = EditorWindow.getSelectedEditor(); + if (ed == null) { + return; + } + ed.saveFile(); + } + + static void saveFileAs(ActionEvent e) { + if (EditorWindow.tabsCount() == 1) { + return; + } + var ed = EditorWindow.getSelectedEditor(); + if (ed == null) { + return; + } + ed.saveFileAs(); + } + + static void saveAllFiles(ActionEvent e) { + EditorWindow.saveAll(); + } + + static void closeFile(ActionEvent e) { + closeTab(e); + } + + static void quit(ActionEvent e) { + closeAllTabs(e); + System.exit(0); + } + + static void newFile(ActionEvent e) { + // TODO: Use a file creator dialog in the future + EditorWindow.addTab(e); + } }