diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..c5f3f6b9 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "java.configuration.updateBuildConfiguration": "interactive" +} \ No newline at end of file diff --git a/diylc/.run/DIYLCStarter.run.xml b/diylc/.run/DIYLCStarter.run.xml new file mode 100644 index 00000000..b9dca84e --- /dev/null +++ b/diylc/.run/DIYLCStarter.run.xml @@ -0,0 +1,16 @@ + + + + \ No newline at end of file diff --git a/diylc/diylc-core/config.properties b/diylc/diylc-core/config.properties deleted file mode 100644 index c6abd215..00000000 --- a/diylc/diylc-core/config.properties +++ /dev/null @@ -1,2 +0,0 @@ -#org.diylc.utils.Constants.CANVAS_COLOR=#005D96 -#org.diylc.utils.Constants.GRID_COLOR=#FFFFFF \ No newline at end of file diff --git a/diylc/diylc-core/src/main/java/org/diylc/components/AbstractCurvedComponent.java b/diylc/diylc-core/src/main/java/org/diylc/components/AbstractCurvedComponent.java index 69458fa4..983eb7d0 100644 --- a/diylc/diylc-core/src/main/java/org/diylc/components/AbstractCurvedComponent.java +++ b/diylc/diylc-core/src/main/java/org/diylc/components/AbstractCurvedComponent.java @@ -76,7 +76,7 @@ public abstract class AbstractCurvedComponent extends AbstractTransparentComp * @param curve * @param g2d * @param componentState - * @param theme + * @param drawingObserver */ protected abstract void drawCurve(Path2D curve, Graphics2D g2d, ComponentState componentState, IDrawingObserver drawingObserver); diff --git a/diylc/diylc-core/src/main/java/org/diylc/components/AbstractTransparentComponent.java b/diylc/diylc-core/src/main/java/org/diylc/components/AbstractTransparentComponent.java index 78a9615d..52b18e84 100644 --- a/diylc/diylc-core/src/main/java/org/diylc/components/AbstractTransparentComponent.java +++ b/diylc/diylc-core/src/main/java/org/diylc/components/AbstractTransparentComponent.java @@ -29,10 +29,13 @@ public abstract class AbstractTransparentComponent extends AbstractComponent< public static byte MAX_ALPHA = 127; - protected byte alpha = MAX_ALPHA; + protected Byte alpha = MAX_ALPHA; @EditableProperty public Byte getAlpha() { + if (alpha == null) { + alpha = MAX_ALPHA; + } return alpha; } diff --git a/diylc/diylc-core/src/main/java/org/diylc/core/BoardUndersideDisplay.java b/diylc/diylc-core/src/main/java/org/diylc/core/BoardUndersideDisplay.java new file mode 100644 index 00000000..1c402bb0 --- /dev/null +++ b/diylc/diylc-core/src/main/java/org/diylc/core/BoardUndersideDisplay.java @@ -0,0 +1,10 @@ +package org.diylc.core; + +public enum BoardUndersideDisplay { + NONE, ABOVE, BELOW, LEFT, RIGHT; + + @Override + public String toString() { + return super.toString().charAt(0) + super.toString().substring(1).toLowerCase(); + } +} diff --git a/diylc/diylc-core/src/main/java/org/diylc/core/IBoard.java b/diylc/diylc-core/src/main/java/org/diylc/core/IBoard.java new file mode 100644 index 00000000..302547d3 --- /dev/null +++ b/diylc/diylc-core/src/main/java/org/diylc/core/IBoard.java @@ -0,0 +1,16 @@ +package org.diylc.core; + +import org.diylc.core.measures.Size; + +import java.awt.geom.Rectangle2D; + +public interface IBoard { + + Rectangle2D getBoardRectangle(); + + BoardUndersideDisplay getBoardUndersideDisplay(); + + Size getUndersideOffset(); + + boolean shouldExportToGerber(); +} diff --git a/diylc/diylc-core/src/main/java/org/diylc/core/gerber/GerberExporter.java b/diylc/diylc-core/src/main/java/org/diylc/core/gerber/GerberExporter.java index 066254c7..e041e9e2 100644 --- a/diylc/diylc-core/src/main/java/org/diylc/core/gerber/GerberExporter.java +++ b/diylc/diylc-core/src/main/java/org/diylc/core/gerber/GerberExporter.java @@ -17,6 +17,7 @@ import org.apache.log4j.Logger; import com.bancika.gerberwriter.DataLayer; import org.diylc.core.ComponentState; +import org.diylc.core.IBoard; import org.diylc.core.IDIYComponent; import org.diylc.core.IView; import org.diylc.core.Project; @@ -30,44 +31,47 @@ public class GerberExporter { private static final Logger LOG = Logger.getLogger(GerberExporter.class); public static void exportGerber(String fileNameBase, Project currentProject, IView view, - Graphics2D graphics2d, String diylcVersion) { - List gerberBoards = - currentProject.getComponents().stream().filter(c -> c instanceof IGerberBoard) - .map(x -> (IGerberBoard) x).collect(Collectors.toList()); + Graphics2D graphics2d, String diylcVersion) { - Map>> boardComponentMap = - new HashMap>>(); + List gerberBoards = + currentProject.getComponents().stream() + .filter(IBoard.class::isInstance) + .map(IBoard.class::cast) + .filter(IBoard::shouldExportToGerber).collect(Collectors.toList()); + + Map>> boardComponentMap = + new HashMap>>(); // DefaultGerberBoard defaultGerberBoard = new DefaultGerberBoard(); List> componentsWithoutBoard = new ArrayList>(); currentProject.getComponents().stream().filter(c -> c instanceof IGerberComponent) - .forEach(c -> { - Point2D firstPoint = c.getControlPoint(0); - IGerberBoard board = gerberBoards.stream() - .filter(b -> b.getBoardRectangle().contains(firstPoint)).findFirst().orElse(null); - if (board == null) { - componentsWithoutBoard.add(c); - } else { - boardComponentMap.computeIfAbsent(board, k -> new ArrayList>()).add(c); - } - }); + .forEach(c -> { + Point2D firstPoint = c.getControlPoint(0); + IBoard board = gerberBoards.stream() + .filter(b -> b.getBoardRectangle().contains(firstPoint)).findFirst().orElse(null); + if (board == null) { + componentsWithoutBoard.add(c); + } else { + boardComponentMap.computeIfAbsent(board, k -> new ArrayList>()).add(c); + } + }); // defaultGerberBoard.setComponents(boardComponentMap.get(defaultGerberBoard)); if (boardComponentMap.isEmpty()) { view.showMessage(LangUtil.translate("Nothing to export."), - LangUtil.translate("Gerber Export"), IView.WARNING_MESSAGE); + LangUtil.translate("Gerber Export"), IView.WARNING_MESSAGE); return; } if (componentsWithoutBoard.size() > 0) { if (view.showConfirmDialog(String.format( - LangUtil.translate("There are some components that are outside of the bounds of boards.%s" - + "They will be ignored unless you add a board component underneath them.%sDo you want to continue?"), - "\n", "\n"), LangUtil.translate("Gerber Export"), IView.YES_NO_OPTION, - IView.WARNING_MESSAGE) != IView.YES_OPTION) { + LangUtil.translate("There are some components that are outside of the bounds of boards.%s" + + "They will be ignored unless you add a board component underneath them.%sDo you want to continue?"), + "\n", "\n"), LangUtil.translate("Gerber Export"), IView.YES_NO_OPTION, + IView.WARNING_MESSAGE) != IView.YES_OPTION) { return; } } @@ -88,15 +92,15 @@ public class GerberExporter { String fileNameOutline = GerberLayer.Outline.formatFileName(fileNameBase, boardComponent.getName()); try { LOG.info(String.format(LangUtil.translate("Exporting outline for board %s to file %s"), - boardComponent.getName(), fileNameOutline)); + boardComponent.getName(), fileNameOutline)); outlineLayer.dumpGerberToFile(fileNameOutline); generatedFiles.add(fileNameOutline); } catch (IOException e) { LOG.error("Error writing gerber file: " + e.getMessage()); view.showMessage( - LangUtil.translate( - "Failed to export the project to gerber. Please check the log for details"), - LangUtil.translate("Gerber Export"), IView.ERROR_MESSAGE); + LangUtil.translate( + "Failed to export the project to gerber. Please check the log for details"), + LangUtil.translate("Gerber Export"), IView.ERROR_MESSAGE); return; } @@ -119,30 +123,30 @@ public class GerberExporter { try { String fileName = layer.formatFileName(fileNameBase, boardComponent.getName()); LOG.info("Exporting layer: " + layer + " for board " + boardComponent.getName() - + " to file: " + fileName); + + " to file: " + fileName); dataLayer.dumpGerberToFile(fileName); generatedFiles.add(fileName); } catch (IOException e) { LOG.error("Error writing gerber file: " + e.getMessage()); view.showMessage( - LangUtil.translate( - "Failed to export the project to gerber. Please check the log for details"), - LangUtil.translate("Gerber Export"), IView.ERROR_MESSAGE); + LangUtil.translate( + "Failed to export the project to gerber. Please check the log for details"), + LangUtil.translate("Gerber Export"), IView.ERROR_MESSAGE); return; } }); }); view.showMessage( - String.format( - LangUtil.translate( - "Gerber export completed successfully. The following files were created:%s"), - "\n\n" + String.join("\n", generatedFiles)), - LangUtil.translate("Gerber Export"), IView.INFORMATION_MESSAGE); + String.format( + LangUtil.translate( + "Gerber export completed successfully. The following files were created:%s"), + "\n\n" + String.join("\n", generatedFiles)), + LangUtil.translate("Gerber Export"), IView.INFORMATION_MESSAGE); LOG.info("Completed export to gerber"); } - + private static void drawComponent(Project currentProject, GerberG2DWrapper g2d, - IDIYComponent c, boolean outlineMode) { + IDIYComponent c, boolean outlineMode) { IGerberComponent gerberComponent = (IGerberComponent) c; g2d.startedDrawingComponent(); if (gerberComponent instanceof IGerberComponentCustom) { @@ -151,9 +155,9 @@ public class GerberExporter { } else if (gerberComponent instanceof IGerberComponentSimple) { IGerberComponentSimple gerberComponentSimple = (IGerberComponentSimple) gerberComponent; g2d.startGerberOutput(gerberComponentSimple.getGerberLayer(), - gerberComponentSimple.getGerberFunction(), gerberComponentSimple.isGerberNegative()); + gerberComponentSimple.getGerberFunction(), gerberComponentSimple.isGerberNegative()); c.draw(g2d, ComponentState.NORMAL, outlineMode, currentProject, g2d); g2d.stopGerberOutput(); } } -} +} \ No newline at end of file diff --git a/diylc/diylc-core/src/main/java/org/diylc/core/gerber/IGerberBoard.java b/diylc/diylc-core/src/main/java/org/diylc/core/gerber/IGerberBoard.java deleted file mode 100644 index 76474d71..00000000 --- a/diylc/diylc-core/src/main/java/org/diylc/core/gerber/IGerberBoard.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.diylc.core.gerber; - -import java.awt.geom.Rectangle2D; - -public interface IGerberBoard { - - Rectangle2D getBoardRectangle(); -} diff --git a/diylc/diylc-core/src/main/java/org/diylc/lang/LangUtil.java b/diylc/diylc-core/src/main/java/org/diylc/lang/LangUtil.java index 55b3824e..6312f093 100644 --- a/diylc/diylc-core/src/main/java/org/diylc/lang/LangUtil.java +++ b/diylc/diylc-core/src/main/java/org/diylc/lang/LangUtil.java @@ -125,25 +125,28 @@ public class LangUtil { public static List getAvailableLanguages() { List res = new ArrayList(); - List files = ResourceUtils.getResourceFiles(LANG_DIR); + Map langContents = ResourceUtils.getResourceContents(LANG_DIR); try { - for (File file : files) { - String key = file.getName().replaceFirst("[.][^.]+$", ""); - Map details = new HashMap(); - try (Stream stream = Files.lines( - Paths.get(file.getAbsolutePath()), StandardCharsets.UTF_8)) { - stream.forEach(s -> { - if (s.contains("=")) { - String[] parts = s.split("="); - if (parts.length == 2) - details.put(parts[0].toLowerCase().trim(), parts[1].trim()); + langContents.entrySet().stream() + .sorted(Map.Entry.comparingByKey()) + .forEach(entry -> { + String key = entry.getKey().replaceFirst("[.][^.]+$", ""); + Map details = new HashMap(); + try { + String content = entry.getValue(); + String[] lines = content.split("\n"); + for (String line : lines) { + if (line.contains("=")) { + String[] parts = line.split("="); + if (parts.length == 2) + details.put(parts[0].toLowerCase().trim(), parts[1].trim()); + } + } + } catch (Exception e) { + LOG.error("Error loading language file", e); } + res.add(new Language(key, details)); }); - } catch (IOException e) { - LOG.error("Error loading language file", e); - } - res.add(new Language(key, details)); - } Collections.sort(res); return res; } catch (Exception e) { diff --git a/diylc/diylc-core/src/main/java/org/diylc/presenter/BuildingBlockManager.java b/diylc/diylc-core/src/main/java/org/diylc/presenter/BuildingBlockManager.java index 45484187..1685f568 100644 --- a/diylc/diylc-core/src/main/java/org/diylc/presenter/BuildingBlockManager.java +++ b/diylc/diylc-core/src/main/java/org/diylc/presenter/BuildingBlockManager.java @@ -18,7 +18,6 @@ package org.diylc.presenter; import java.io.*; -import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -42,7 +41,7 @@ import org.diylc.serialization.ProjectFileManager; public class BuildingBlockManager { - private static final String BLOCKS_FILE_NAME = "blocks.xml"; + private static final String BLOCKS_FILE_NAME = "import-defaults/blocks.xml"; private static final Logger LOG = Logger.getLogger(VariantManager.class); diff --git a/diylc/diylc-core/src/main/java/org/diylc/presenter/ComponentProcessor.java b/diylc/diylc-core/src/main/java/org/diylc/presenter/ComponentProcessor.java index 7503354c..4a7c1409 100644 --- a/diylc/diylc-core/src/main/java/org/diylc/presenter/ComponentProcessor.java +++ b/diylc/diylc-core/src/main/java/org/diylc/presenter/ComponentProcessor.java @@ -26,12 +26,8 @@ import java.awt.Image; import java.awt.RenderingHints; import java.awt.image.BufferedImage; import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.lang.reflect.Modifier; +import java.util.*; import javax.swing.Icon; import javax.swing.ImageIcon; import org.apache.log4j.Logger; @@ -52,6 +48,11 @@ import org.diylc.core.annotations.EditableProperty; import org.diylc.core.annotations.KeywordPolicy; import org.diylc.lang.LangUtil; +import org.reflections.Reflections; +import org.reflections.util.ConfigurationBuilder; +import org.reflections.util.FilterBuilder; + +import static org.reflections.scanners.Scanners.TypesAnnotated; /** * Utility class with component processing methods. @@ -68,6 +69,7 @@ public class ComponentProcessor { private Map propertyValidatorCache; private Map componentTypeMap; private Map componentTransformerMap; + private Map> componentTypes; public static ComponentProcessor getInstance() { if (instance == null) { @@ -138,6 +140,10 @@ public class ComponentProcessor { Graphics2D g2d = (Graphics2D) image.getGraphics(); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); + g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, + RenderingHints.VALUE_INTERPOLATION_BICUBIC); + g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, + RenderingHints.VALUE_FRACTIONALMETRICS_ON); // g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, // RenderingHints.VALUE_STROKE_PURE); componentInstance.drawIcon(g2d, Presenter.ICON_SIZE, Presenter.ICON_SIZE); @@ -225,6 +231,50 @@ public class ComponentProcessor { return result; } + public Map> getComponentTypes() { + if (componentTypes == null) { + LOG.info("Loading component types."); + componentTypes = new HashMap>(); + Reflections reflections = new Reflections( + new ConfigurationBuilder() + .forPackage("org.diylc") + .filterInputsBy(new FilterBuilder().includePackage("org.diylc.components")) + .setScanners(TypesAnnotated)); + Set> componentTypeClasses = null; + try { + componentTypeClasses = reflections.getTypesAnnotatedWith(ComponentDescriptor.class, false); + + for (Class clazz : componentTypeClasses) { + if (!Modifier.isAbstract(clazz.getModifiers()) && IDIYComponent.class.isAssignableFrom(clazz)) { + ComponentType componentType = + ComponentProcessor.getInstance().extractComponentTypeFrom((Class>) clazz); + if (componentType == null) + continue; + + // just to store in the cache + ComponentProcessor.getInstance().extractProperties(clazz); + + List nestedList; + if (componentTypes.containsKey(componentType.getCategory())) { + nestedList = componentTypes.get(componentType.getCategory()); + } else { + nestedList = new ArrayList(); + componentTypes.put(componentType.getCategory(), nestedList); + } + nestedList.add(componentType); + } + } + + for (Map.Entry> e : componentTypes.entrySet()) { + LOG.debug(e.getKey() + ": " + e.getValue()); + } + } catch (Exception e) { + LOG.error("Error loading component types", e); + } + } + return componentTypes; + } + /** * Returns properties that have the same value for all the selected components. * diff --git a/diylc/diylc-core/src/main/java/org/diylc/presenter/DatasheetService.java b/diylc/diylc-core/src/main/java/org/diylc/presenter/DatasheetService.java index abff8506..7dc1812e 100644 --- a/diylc/diylc-core/src/main/java/org/diylc/presenter/DatasheetService.java +++ b/diylc/diylc-core/src/main/java/org/diylc/presenter/DatasheetService.java @@ -17,10 +17,7 @@ */ package org.diylc.presenter; -import java.io.BufferedInputStream; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; +import java.io.*; import java.net.URL; import java.util.HashMap; import java.util.List; @@ -55,16 +52,15 @@ public class DatasheetService { private DatasheetService() {} public List loadDatasheet(Class clazz) { - ClassLoader classloader = Thread.currentThread().getContextClassLoader(); return datasheetCache.computeIfAbsent(clazz.getCanonicalName(), key -> { String fileName = clazz.getSimpleName() + ".datasheet"; LOG.info("Loading datasheet file for " + fileName); - URL resource = classloader.getResource(fileName); - if (resource == null) { + InputStream inputStream = clazz.getResourceAsStream("/datasheets/" + fileName); + if (inputStream == null) { LOG.warn("Datasheet file not found: " + fileName); return null; } - try (BufferedInputStream in = new BufferedInputStream(resource.openStream())) { + try (BufferedInputStream in = new BufferedInputStream(inputStream)) { try (BufferedReader reader = new BufferedReader(new InputStreamReader(in))) { List types = diff --git a/diylc/diylc-core/src/main/java/org/diylc/presenter/DrawingManager.java b/diylc/diylc-core/src/main/java/org/diylc/presenter/DrawingManager.java index f2920b1d..c272692e 100644 --- a/diylc/diylc-core/src/main/java/org/diylc/presenter/DrawingManager.java +++ b/diylc/diylc-core/src/main/java/org/diylc/presenter/DrawingManager.java @@ -49,20 +49,9 @@ import org.apache.log4j.Logger; import org.diylc.appframework.miscutils.IConfigurationManager; import org.diylc.appframework.simplemq.MessageDispatcher; -import org.diylc.common.DrawOption; -import org.diylc.common.EventType; -import org.diylc.common.GridType; -import org.diylc.common.IComponentFilter; -import org.diylc.common.IPlugInPort; -import org.diylc.common.ObjectCache; -import org.diylc.core.ComponentForRender; -import org.diylc.core.ComponentState; -import org.diylc.core.IContinuity; -import org.diylc.core.IDIYComponent; -import org.diylc.core.ILayeredComponent; -import org.diylc.core.Project; -import org.diylc.core.Theme; -import org.diylc.core.VisibilityPolicy; +import org.diylc.common.*; +import org.diylc.components.AbstractTransparentComponent; +import org.diylc.core.*; import org.diylc.core.measures.Size; import org.diylc.core.measures.SizeUnit; import org.diylc.netlist.ContinuityGraph; @@ -78,6 +67,7 @@ import org.diylc.utils.Constants; public class DrawingManager { private static final Logger LOG = Logger.getLogger(DrawingManager.class); + public static final byte MIRROR_ALPHA = 64; public static int CONTROL_POINT_SIZE = 7; public static double EXTRA_SPACE = 0.25; @@ -195,38 +185,35 @@ public class DrawingManager { G2DWrapper g2dWrapper = new G2DWrapper(g2d, zoom); - if (drawOptions.contains(DrawOption.ANTIALIASING)) { - g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, - RenderingHints.VALUE_TEXT_ANTIALIAS_ON); - } else { - g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); - g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, - RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); + configureRenderingHints(g2d, drawOptions); + + // group components with boards that contain them + Map>> boardMap = project.getComponents().stream() + .filter(IBoard.class::isInstance) + .map(IBoard.class::cast) + .filter(b -> b.getBoardUndersideDisplay() != BoardUndersideDisplay.NONE) + .collect(Collectors.toMap(x -> x, x -> new ArrayList>())); + Map, Set> componentBoardMap = new HashMap, Set>(); + + for (IBoard board : boardMap.keySet()) { + Rectangle2D boardRect = board.getBoardRectangle(); + for (IDIYComponent c : project.getComponents()) { + if (c == board) { + continue; + } + boolean include = true; + for (int i = 0; i < c.getControlPointCount(); i++) { + if (!boardRect.contains(c.getControlPoint(i))) { + include = false; + break; + } + } + if (include) { + boardMap.get(board).add(c); + componentBoardMap.computeIfAbsent(c, key -> new HashSet()).add(board); + } + } } - if (configManager.readBoolean(IPlugInPort.HI_QUALITY_RENDER_KEY, false)) { - g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, - RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY); - g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, - RenderingHints.VALUE_COLOR_RENDER_QUALITY); - g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); - g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE); - g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, - RenderingHints.VALUE_INTERPOLATION_BILINEAR); - // g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, - // RenderingHints.VALUE_STROKE_PURE); - } else { - g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, - RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED); - g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, - RenderingHints.VALUE_COLOR_RENDER_SPEED); - g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED); - g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_DISABLE); - g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, - RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR); - } - g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, - RenderingHints.VALUE_FRACTIONALMETRICS_OFF); // AffineTransform initialTx = g2d.getTransform(); Dimension canvasDimension = @@ -297,7 +284,7 @@ public class DrawingManager { // drawn in the same state. boolean trackArea = lastDrawnStateMap.get(component) != state; - synchronized (g2d) { + synchronized (this) { g2dWrapper.startedDrawingComponent(i); if (!trackArea) { g2dWrapper.stopTracking(); @@ -312,11 +299,7 @@ public class DrawingManager { long componentStart = System.nanoTime(); try { - if (drawOptions.contains(DrawOption.ENABLE_CACHING)) // go through the DrawingCache - DrawingCache.Instance.draw(component, g2dWrapper, state, - drawOptions.contains(DrawOption.OUTLINE_MODE), project, zoom, scaleFactor, i, visibleRect); - else // go straight to the wrapper - component.draw(g2dWrapper, state, outlineMode, project, g2dWrapper); + drawComponent(project, drawOptions, scaleFactor, visibleRect, component, g2dWrapper, state, zoom, i, outlineMode); if (g2dWrapper.isTrackingContinuityArea()) { LOG.info("Component " + component.getName() + " of type " @@ -349,6 +332,29 @@ public class DrawingManager { componentAreaMap.put(component, area); lastDrawnStateMap.put(component, state); } + + // Mirror components that belong to boards that need to be mirrored + if (componentBoardMap.containsKey(component)) { + @SuppressWarnings("unchecked") + ComponentType componentType = ComponentProcessor.getInstance() + .extractComponentTypeFrom((Class>) component.getClass()); + if (componentType.getTransformer() != null) { + Set boards = componentBoardMap.get(component); + for (IBoard board : boards) { + drawMirroredComponent(project, board, component, componentType, g2dWrapper, state, outlineMode); + } + } + } + + // if a component itself is a board that needs to be mirrored, do it + if (IBoard.class.isInstance(component) && componentBoardMap.values().stream() + .anyMatch(boards -> boards.contains(component))) { + ComponentType componentType = ComponentProcessor.getInstance() + .extractComponentTypeFrom((Class>) component.getClass()); + if (componentType.getTransformer() != null) { + drawMirroredComponent(project, (IBoard) component, component, componentType, g2dWrapper, state, outlineMode); + } + } } } @@ -510,6 +516,86 @@ public class DrawingManager { return failedComponents; } + private static void drawMirroredComponent(Project project, IBoard board, IDIYComponent component, + ComponentType componentType, G2DWrapper g2dWrapper, ComponentState state, boolean outlineMode) { + double offset = board.getUndersideOffset().convertToPixels(); + Rectangle2D boardRectangle = board.getBoardRectangle(); + try { + IDIYComponent clonedComponent = component.clone(); + int direction = 0; + Point2D pivotPoint = new Point2D.Double(); + switch (board.getBoardUndersideDisplay()) { + case ABOVE: + direction = IComponentTransformer.VERTICAL; + pivotPoint.setLocation(boardRectangle.getMinX(), boardRectangle.getMinY() - offset / 2); + break; + case BELOW: + direction = IComponentTransformer.VERTICAL; + pivotPoint.setLocation(boardRectangle.getMinX(), boardRectangle.getMaxY() + offset / 2); + break; + case LEFT: + direction = IComponentTransformer.HORIZONTAL; + pivotPoint.setLocation(boardRectangle.getMinX() - offset / 2, boardRectangle.getMinY()); + break; + case RIGHT: + direction = IComponentTransformer.HORIZONTAL; + pivotPoint.setLocation(boardRectangle.getMaxX() + offset / 2, boardRectangle.getMinY()); + break; + } + componentType.getTransformer().mirror(clonedComponent, pivotPoint, direction); + if (AbstractTransparentComponent.class.isInstance(clonedComponent)) { + AbstractTransparentComponent transparentComponent = (AbstractTransparentComponent) clonedComponent; + transparentComponent.setAlpha(MIRROR_ALPHA); + } + clonedComponent.draw(g2dWrapper, state, outlineMode, project, g2dWrapper); + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + private static void drawComponent(Project project, Set drawOptions, Double scaleFactor, Rectangle2D visibleRect, IDIYComponent component, G2DWrapper g2dWrapper, ComponentState state, double zoom, int i, boolean outlineMode) { + if (drawOptions.contains(DrawOption.ENABLE_CACHING)) // go through the DrawingCache + DrawingCache.Instance.draw(component, g2dWrapper, state, + drawOptions.contains(DrawOption.OUTLINE_MODE), project, zoom, scaleFactor, i, visibleRect); + else // go straight to the wrapper + component.draw(g2dWrapper, state, outlineMode, project, g2dWrapper); + } + + private void configureRenderingHints(Graphics2D g2d, Set drawOptions) { + if (drawOptions.contains(DrawOption.ANTIALIASING)) { + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + } else { + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); + g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); + } + if (configManager.readBoolean(IPlugInPort.HI_QUALITY_RENDER_KEY, false)) { + g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, + RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY); + g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, + RenderingHints.VALUE_COLOR_RENDER_QUALITY); + g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); + g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE); + g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, + RenderingHints.VALUE_INTERPOLATION_BILINEAR); + // g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, + // RenderingHints.VALUE_STROKE_PURE); + } else { + g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, + RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED); + g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, + RenderingHints.VALUE_COLOR_RENDER_SPEED); + g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED); + g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_DISABLE); + g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, + RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR); + } + g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, + RenderingHints.VALUE_FRACTIONALMETRICS_OFF); + } + private double zoomCached = 0; private Dimension canvasDimensionCached; private double extraSpaceCached; diff --git a/diylc/diylc-core/src/main/java/org/diylc/presenter/Presenter.java b/diylc/diylc-core/src/main/java/org/diylc/presenter/Presenter.java index b6e6587e..a0c13fda 100644 --- a/diylc/diylc-core/src/main/java/org/diylc/presenter/Presenter.java +++ b/diylc/diylc-core/src/main/java/org/diylc/presenter/Presenter.java @@ -78,7 +78,6 @@ import org.diylc.core.Project; import org.diylc.core.Template; import org.diylc.core.Theme; import org.diylc.core.VisibilityPolicy; -import org.diylc.core.annotations.ComponentDescriptor; import org.diylc.core.annotations.IAutoCreator; import org.diylc.core.gerber.GerberExporter; import org.diylc.core.measures.Size; @@ -94,11 +93,6 @@ import org.diylc.test.DIYTest; import org.diylc.test.Snapshot; import org.diylc.utils.Constants; import org.diylc.utils.ReflectionUtils; -import org.reflections.Reflections; -import org.reflections.util.ConfigurationBuilder; -import org.reflections.util.FilterBuilder; - -import static org.reflections.scanners.Scanners.TypesAnnotated; /** * The main presenter class, contains core app logic and drawing routines. @@ -135,6 +129,9 @@ public class Presenter implements IPlugInPort, IConfigListener { private static final Logger LOG = Logger.getLogger(Presenter.class); + public static final Double[] ZOOM_LEVELS = + {0.25d, 0.3333d, 0.5d, 0.6667d, 0.75d, 1d, 1.25d, 1.5d, 2d, 2.5d, 3d}; + public static VersionNumber CURRENT_VERSION = null; private static List RECENT_VERSIONS = null; @@ -147,7 +144,6 @@ public class Presenter implements IPlugInPort, IConfigListener { private static final int MAX_RECENT_FILES = 20; private Project currentProject; - private Map> componentTypes; // Maps component class names to ComponentType objects. private List plugIns; @@ -242,7 +238,7 @@ public class Presenter implements IPlugInPort, IConfigListener { @Override public java.lang.Double[] getAvailableZoomLevels() { - return new java.lang.Double[] {0.25d, 0.3333d, 0.5d, 0.6667d, 0.75d, 1d, 1.25d, 1.5d, 2d, 2.5d, 3d}; + return ZOOM_LEVELS; } @Override @@ -424,47 +420,7 @@ public class Presenter implements IPlugInPort, IConfigListener { @SuppressWarnings("unchecked") @Override public Map> getComponentTypes() { - if (componentTypes == null) { - LOG.info("Loading component types."); - componentTypes = new HashMap>(); - Reflections reflections = new Reflections( - new ConfigurationBuilder() - .forPackage("org.diylc") - .filterInputsBy(new FilterBuilder().includePackage("org.diylc.components")) - .setScanners(TypesAnnotated)); - Set> componentTypeClasses = null; - try { - componentTypeClasses = reflections.getTypesAnnotatedWith(ComponentDescriptor.class, false); - - for (Class clazz : componentTypeClasses) { - if (!Modifier.isAbstract(clazz.getModifiers()) && IDIYComponent.class.isAssignableFrom(clazz)) { - ComponentType componentType = - ComponentProcessor.getInstance().extractComponentTypeFrom((Class>) clazz); - if (componentType == null) - continue; - - // just to store in the cache - ComponentProcessor.getInstance().extractProperties(clazz); - - List nestedList; - if (componentTypes.containsKey(componentType.getCategory())) { - nestedList = componentTypes.get(componentType.getCategory()); - } else { - nestedList = new ArrayList(); - componentTypes.put(componentType.getCategory(), nestedList); - } - nestedList.add(componentType); - } - } - - for (Map.Entry> e : componentTypes.entrySet()) { - LOG.debug(e.getKey() + ": " + e.getValue()); - } - } catch (Exception e) { - LOG.error("Error loading component types", e); - } - } - return componentTypes; + return ComponentProcessor.getInstance().getComponentTypes(); } @SuppressWarnings({"unchecked"}) @@ -2559,7 +2515,8 @@ public class Presenter implements IPlugInPort, IConfigListener { } } try { - BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream("variants.xml")); + BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream( + "import-defaults/variants.xml")); XStream xStream = new XStream(new DomDriver()); xStream.addPermission(AnyTypePermission.ANY); ProjectFileManager.xStreamSerializer.toXML(defaultVariantMap, out); diff --git a/diylc/diylc-core/src/main/java/org/diylc/presenter/VariantManager.java b/diylc/diylc-core/src/main/java/org/diylc/presenter/VariantManager.java index 4761b4e4..6e857688 100644 --- a/diylc/diylc-core/src/main/java/org/diylc/presenter/VariantManager.java +++ b/diylc/diylc-core/src/main/java/org/diylc/presenter/VariantManager.java @@ -21,7 +21,6 @@ import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; -import java.net.URL; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Collections; @@ -46,7 +45,7 @@ import org.diylc.serialization.ProjectFileManager; public class VariantManager { - private static final String VARIANTS_FILE_NAME = "variants.xml"; + private static final String VARIANTS_FILE_NAME = "import-defaults/variants.xml"; private static final Logger LOG = Logger.getLogger(VariantManager.class); diff --git a/diylc/diylc-core/src/main/java/org/diylc/utils/ResourceUtils.java b/diylc/diylc-core/src/main/java/org/diylc/utils/ResourceUtils.java index 6a1cbb25..2b3d32f1 100644 --- a/diylc/diylc-core/src/main/java/org/diylc/utils/ResourceUtils.java +++ b/diylc/diylc-core/src/main/java/org/diylc/utils/ResourceUtils.java @@ -24,36 +24,78 @@ package org.diylc.utils; import org.apache.log4j.Logger; import org.diylc.lang.LangUtil; -import java.io.File; import java.io.IOException; -import java.net.URISyntaxException; +import java.io.InputStream; import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.List; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; public class ResourceUtils { - private static final Logger LOG = Logger.getLogger(LangUtil.class); + private static final Logger LOG = Logger.getLogger(ResourceUtils.class); - public static List getResourceFiles(String dir) { - List files = new ArrayList<>(); - URL url = LangUtil.class.getResource("/" + dir); - Path path = null; + public static Map getResourceContents(String dir) { + Map contents = new HashMap<>(); + try { - path = Paths.get(url.toURI()); - Files.walk(path, 5).forEach(p -> { - if (!p.toFile().isDirectory()) { - files.add(p.toFile()); + // Get all resources in the directory + URL dirUrl = ResourceUtils.class.getClassLoader().getResource(dir); + if (dirUrl != null) { + if (dirUrl.getProtocol().equals("jar")) { + // Running from JAR + String jarPath = dirUrl.getPath(); + // Remove the "file:" prefix and decode the URL + jarPath = URLDecoder.decode(jarPath.substring(5, jarPath.indexOf("!")), StandardCharsets.UTF_8); + JarFile jarFile = new JarFile(jarPath); + try { + jarFile.stream() + .filter(entry -> entry.getName().startsWith(dir + "/") && !entry.isDirectory()) + .forEach(entry -> { + try { + String relativePath = entry.getName().substring(dir.length() + 1); + // Read the entire file content as string + String content = new String(jarFile.getInputStream(entry).readAllBytes(), StandardCharsets.UTF_8); + contents.put(relativePath, content); + } catch (IOException e) { + LOG.warn("Could not read resource: " + entry.getName(), e); + } + }); + } finally { + try { + jarFile.close(); + } catch (IOException e) { + LOG.warn("Could not close JAR file", e); + } + } + } else { + // Running from filesystem + java.io.File dirFile = new java.io.File(dirUrl.toURI()); + if (dirFile.exists() && dirFile.isDirectory()) { + java.io.File[] files = dirFile.listFiles(); + if (files != null) { + for (java.io.File file : files) { + if (file.isFile()) { + try { + String relativePath = file.getName(); + String content = new String(java.nio.file.Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8); + contents.put(relativePath, content); + } catch (IOException e) { + LOG.warn("Could not read file: " + file, e); + } + } + } + } + } } - }); - } catch (URISyntaxException e) { - LOG.error("Error loading language file", e); - } catch (IOException e) { - LOG.error("Error loading language file", e); + } + } catch (Exception e) { + LOG.error("Error loading resources from directory: " + dir, e); } - return files; + + return contents; } } diff --git a/diylc/diylc-core/src/main/resources/blocks.xml b/diylc/diylc-core/src/main/resources/import-defaults/blocks.xml similarity index 100% rename from diylc/diylc-core/src/main/resources/blocks.xml rename to diylc/diylc-core/src/main/resources/import-defaults/blocks.xml diff --git a/diylc/diylc-core/src/main/resources/variants.xml b/diylc/diylc-core/src/main/resources/import-defaults/variants.xml similarity index 100% rename from diylc/diylc-core/src/main/resources/variants.xml rename to diylc/diylc-core/src/main/resources/import-defaults/variants.xml diff --git a/diylc/diylc-core/src/main/resources/themes/Gray.xml b/diylc/diylc-core/src/main/resources/themes/Gray.xml new file mode 100644 index 00000000..1f5966e0 --- /dev/null +++ b/diylc/diylc-core/src/main/resources/themes/Gray.xml @@ -0,0 +1,27 @@ + + Gray + + 170 + 170 + 170 + 255 + + + 150 + 150 + 150 + 255 + + + 100 + 100 + 100 + 255 + + + 0 + 0 + 0 + 255 + + \ No newline at end of file diff --git a/diylc/diylc-core/src/main/resources/update.xml b/diylc/diylc-core/src/main/resources/update.xml index 967e8b2a..a4f2bed2 100644 --- a/diylc/diylc-core/src/main/resources/update.xml +++ b/diylc/diylc-core/src/main/resources/update.xml @@ -246,9 +246,13 @@ 1 0 - 2025-03-09 00:00:00.000 CET + 2025-03-24 00:00:00.000 CET + + NEW_FEATURE + Added ability to render the underside of boards along with the top side for easier validation, building and debugging + NEW_FEATURE Configurable 'High DPI Rendering' feature which makes the diagram smoother on high-resolution displays but can affect performance @@ -257,6 +261,10 @@ IMPROVEMENT Significantly improved rendering performance + + IMPROVEMENT + Increased initial memory allocation to 1GB for smoother performance + IMPROVEMENT Upgraded source code structure to modern standards and introduced Maven @@ -271,7 +279,7 @@ IMPROVEMENT - Updated the windows installer to avoid false positive virus detection + Updated the windows installer (hopefully) to avoid false positive anti-virus detection BUG_FIX @@ -281,6 +289,10 @@ BUG_FIX Rotating selected components sometimes wacks the alignment off the grid + + BUG_FIX + Ctrl+X (Command+X) shortcut for Cut action doesn't work because 'Project Explorer' steals the focus on X key press + https://github.com/bancika/diy-layout-creator/releases diff --git a/diylc/diylc-core/src/test/java/org/diylc/presenter/DatasheetServiceTest.java b/diylc/diylc-core/src/test/java/org/diylc/presenter/DatasheetServiceTest.java index 08fdb8ee..d68a8e64 100644 --- a/diylc/diylc-core/src/test/java/org/diylc/presenter/DatasheetServiceTest.java +++ b/diylc/diylc-core/src/test/java/org/diylc/presenter/DatasheetServiceTest.java @@ -1,266 +1,80 @@ package org.diylc.presenter; -import static org.junit.Assert.*; -import static org.mockito.Mockito.*; - -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.List; - import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; -@RunWith(MockitoJUnitRunner.class) +import java.util.List; + +import static org.junit.Assert.*; + public class DatasheetServiceTest { - private DatasheetService service; - - @Mock - private ClassLoader mockClassLoader; - + private static final Class TEST_CLASS = DatasheetServiceTest.class; + @Before public void setUp() { service = DatasheetService.getInstance(); - service.clearCache(); // Clear cache before each test - Thread.currentThread().setContextClassLoader(mockClassLoader); + service.clearCache(); } - + @Test - public void testLoadDatasheet() throws Exception { - // Create a mock datasheet content - String datasheetContent = - "1N4001,50V,1A,1.1V\n" + - "1N4002,100V,1A,1.1V\n" + - "1N4003,200V,1A,1.1V"; - - // Create a mock URL that returns our test content - URL mockUrl = mock(URL.class); - when(mockUrl.openStream()).thenReturn( - new ByteArrayInputStream(datasheetContent.getBytes())); - - // Setup the mock ClassLoader to return our mock URL - when(mockClassLoader.getResource("TestComponent.datasheet")) - .thenReturn(mockUrl); - - // Test loading the datasheet - List result = service.loadDatasheet(TestComponent.class); - - // Verify results - assertNotNull("Datasheet should not be null", result); - assertEquals("Should have 3 entries", 3, result.size()); - - // Verify first entry - String[] firstEntry = result.get(0); - assertEquals("1N4001", firstEntry[0]); - assertEquals("50V", firstEntry[1]); - assertEquals("1A", firstEntry[2]); - assertEquals("1.1V", firstEntry[3]); - - // Verify second entry - String[] secondEntry = result.get(1); - assertEquals("1N4002", secondEntry[0]); - assertEquals("100V", secondEntry[1]); - - // Verify third entry - String[] thirdEntry = result.get(2); - assertEquals("1N4003", thirdEntry[0]); - assertEquals("200V", thirdEntry[1]); + public void testLoadDatasheet() { + List result = service.loadDatasheet(TEST_CLASS); + assertNotNull(result); + assertEquals(4, result.size()); + assertArrayEquals(new String[]{"TEST", "KEY", "10.0", "20.0"}, result.get(0)); } - + @Test public void testLoadDatasheetFileNotFound() { - // Setup the mock ClassLoader to return null (file not found) - when(mockClassLoader.getResource("TestComponent.datasheet")) - .thenReturn(null); - - List result = service.loadDatasheet(TestComponent.class); - - assertNull("Result should be null when file is not found", result); + List result = service.loadDatasheet(String.class); + assertNull(result); } - + @Test - public void testLookupExactMatch() throws Exception { - // Create a mock datasheet content - String datasheetContent = - "TEST,KEY,10.0\n" + - "TEST,KEY,20.0\n" + - "TEST,OTHER,15.0\n" + - "OTHER,KEY,10.0"; - - URL mockUrl = mock(URL.class); - when(mockUrl.openStream()).thenReturn( - new ByteArrayInputStream(datasheetContent.getBytes())); - when(mockClassLoader.getResource("DatasheetServiceTest.datasheet")) - .thenReturn(mockUrl); - - // Create test data - String[] result = service.lookup( - DatasheetServiceTest.class, // Using test class itself as component class - 0.1, // 0.1% tolerance - "TEST|KEY", // Key to look up - 10.0 // Value to match - ); - - assertNotNull("Should find matching entry", result); - assertEquals("TEST", result[0]); - assertEquals("KEY", result[1]); + public void testLookupExactMatch() { + String[] result = service.lookup(TEST_CLASS, 0.0, "TEST|KEY", 10.0); + assertNotNull(result); assertEquals("10.0", result[2]); } - + @Test - public void testLookupWithinTolerance() throws Exception { - // Create a mock datasheet content - String datasheetContent = - "TEST,KEY,10.0\n" + - "TEST,KEY,20.0\n" + - "TEST,OTHER,15.0\n" + - "OTHER,KEY,10.0"; - - URL mockUrl = mock(URL.class); - when(mockUrl.openStream()).thenReturn( - new ByteArrayInputStream(datasheetContent.getBytes())); - when(mockClassLoader.getResource("DatasheetServiceTest.datasheet")) - .thenReturn(mockUrl); - - // Should match 10.0 with 5% tolerance when looking for 10.2 - String[] result = service.lookup( - DatasheetServiceTest.class, - 5.0, // 5% tolerance - "TEST|KEY", - 10.2 // Should match 10.0 within 5% tolerance - ); - - assertNotNull("Should find matching entry within tolerance", result); + public void testLookupWithinTolerance() { + String[] result = service.lookup(TEST_CLASS, 5.0, "TEST|KEY", 10.5); + assertNotNull(result); assertEquals("10.0", result[2]); } - + @Test - public void testLookupNoMatch() throws Exception { - // Create a mock datasheet content - String datasheetContent = - "TEST,KEY,10.0\n" + - "TEST,KEY,20.0\n" + - "TEST,OTHER,15.0\n" + - "OTHER,KEY,10.0"; - - URL mockUrl = mock(URL.class); - when(mockUrl.openStream()).thenReturn( - new ByteArrayInputStream(datasheetContent.getBytes())); - when(mockClassLoader.getResource("DatasheetServiceTest.datasheet")) - .thenReturn(mockUrl); - - // Should not match when value is outside tolerance - String[] result = service.lookup( - DatasheetServiceTest.class, - 1.0, // 1% tolerance - "TEST|KEY", - 15.0 // No value close enough to match - ); - - assertNull("Should not find matching entry", result); + public void testLookupOutsideTolerance() { + String[] result = service.lookup(TEST_CLASS, 5.0, "TEST|KEY", 12.0); + assertNull(result); } - + @Test - public void testLookupNonexistentKey() throws Exception { - // Create a mock datasheet content - String datasheetContent = - "TEST,KEY,10.0\n" + - "TEST,KEY,20.0\n" + - "TEST,OTHER,15.0\n" + - "OTHER,KEY,10.0"; - - URL mockUrl = mock(URL.class); - when(mockUrl.openStream()).thenReturn( - new ByteArrayInputStream(datasheetContent.getBytes())); - when(mockClassLoader.getResource("DatasheetServiceTest.datasheet")) - .thenReturn(mockUrl); - - String[] result = service.lookup( - DatasheetServiceTest.class, - 0.1, - "NONEXISTENT|KEY", // Key that doesn't exist in datasheet - 10.0 - ); - - assertNull("Should not find matching entry for nonexistent key", result); + public void testLookupNoMatch() { + String[] result = service.lookup(TEST_CLASS, 0.0, "TEST,KEY", 30.0); + assertNull(result); } - + @Test - public void testLookupWithTolerance() throws Exception { - // Create a mock datasheet content with resistor values - String datasheetContent = - "0805,1%,100,0.125W\n" + - "0805,1%,220,0.125W\n" + - "0805,1%,470,0.125W"; - - URL mockUrl = mock(URL.class); - when(mockUrl.openStream()).thenReturn( - new ByteArrayInputStream(datasheetContent.getBytes())); - when(mockClassLoader.getResource("TestComponent.datasheet")) - .thenReturn(mockUrl); - - // Test lookup with 5% tolerance (should match 220 when looking for 225) - String[] result = service.lookup(TestComponent.class, 5.0, "0805|1%", 225.0); - - assertNotNull("Should find matching entry within tolerance", result); - assertEquals("0805", result[0]); - assertEquals("1%", result[1]); - assertEquals("220", result[2]); + public void testLookupNonexistentKey() { + String[] result = service.lookup(TEST_CLASS, 0.0, "NONEXISTENT,KEY", 10.0); + assertNull(result); } - + @Test - public void testLookupOutsideTolerance() throws Exception { - // Create a mock datasheet content - String datasheetContent = - "0805,1%,100,0.125W\n" + - "0805,1%,220,0.125W\n" + - "0805,1%,470,0.125W"; - - URL mockUrl = mock(URL.class); - when(mockUrl.openStream()).thenReturn( - new ByteArrayInputStream(datasheetContent.getBytes())); - when(mockClassLoader.getResource("TestComponent.datasheet")) - .thenReturn(mockUrl); - - // Test lookup with value outside tolerance - String[] result = service.lookup(TestComponent.class, 1.0, "0805|1%", 250.0); - - assertNull("Should not find matching entry outside tolerance", result); + public void testLookupWithTolerance() { + String[] result = service.lookup(TEST_CLASS, 50.0, "TEST|KEY", 15.0); + assertNotNull(result); + assertEquals("10.0", result[2]); } - + @Test - public void testLookupMultipleValues() throws Exception { - // Create a mock datasheet content with multiple value matches - String datasheetContent = - "TO220,NPN,50,5,0.7\n" + // Vce, Ic, Vbe - "TO220,NPN,60,8,0.7\n" + - "TO220,NPN,100,10,0.7"; - - URL mockUrl = mock(URL.class); - when(mockUrl.openStream()).thenReturn( - new ByteArrayInputStream(datasheetContent.getBytes())); - when(mockClassLoader.getResource("TestComponent.datasheet")) - .thenReturn(mockUrl); - - // Test lookup matching multiple values within tolerance - String[] result = service.lookup(TestComponent.class, 5.0, "TO220|NPN", - 98.0, 9.8, 0.71); - - assertNotNull("Should find matching entry for multiple values", result); - assertEquals("TO220", result[0]); - assertEquals("NPN", result[1]); - assertEquals("100", result[2]); - assertEquals("10", result[3]); - assertEquals("0.7", result[4]); + public void testLookupMultipleValues() { + String[] result = service.lookup(TEST_CLASS, 0.0, "TEST|KEY", 10.0, 20.0); + assertNotNull(result); + assertEquals("10.0", result[2]); + assertEquals("20.0", result[3]); } - - // Test component class - private static class TestComponent { - // Empty class just for testing - } -} \ No newline at end of file +} diff --git a/diylc/diylc-core/src/test/resources/datasheets/DatasheetServiceTest.datasheet b/diylc/diylc-core/src/test/resources/datasheets/DatasheetServiceTest.datasheet new file mode 100644 index 00000000..2712a0d2 --- /dev/null +++ b/diylc/diylc-core/src/test/resources/datasheets/DatasheetServiceTest.datasheet @@ -0,0 +1,4 @@ +TEST,KEY,10.0,20.0 +TEST,KEY,20.0,30.0 +TEST,OTHER,15.0,25.0 +OTHER,KEY,10.0,20.0 \ No newline at end of file diff --git a/diylc/diylc-core/src/test/resources/org/diylc/presenter/DatasheetServiceTest.datasheet b/diylc/diylc-core/src/test/resources/org/diylc/presenter/DatasheetServiceTest.datasheet deleted file mode 100644 index 5249c552..00000000 --- a/diylc/diylc-core/src/test/resources/org/diylc/presenter/DatasheetServiceTest.datasheet +++ /dev/null @@ -1,4 +0,0 @@ -TEST,KEY,10.0 mm -TEST,KEY,20.0 mm -TEST,OTHER,15.0 mm -OTHER,KEY,10.0 mm \ No newline at end of file diff --git a/diylc/diylc-library/.classpath b/diylc/diylc-library/.classpath deleted file mode 100644 index 05a589ec..00000000 --- a/diylc/diylc-library/.classpath +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/diylc/diylc-library/.project b/diylc/diylc-library/.project deleted file mode 100644 index 0f0c953c..00000000 --- a/diylc/diylc-library/.project +++ /dev/null @@ -1,34 +0,0 @@ - - - diylc-library - - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.eclipse.m2e.core.maven2Builder - - - - - - org.eclipse.m2e.core.maven2Nature - org.eclipse.jdt.core.javanature - - - - 1741597247360 - - 30 - - org.eclipse.core.resources.regexFilterMatcher - node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ - - - - diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/AbstractLeadedComponent.java b/diylc/diylc-library/src/main/java/org/diylc/components/AbstractLeadedComponent.java index cdb8d891..fe9d7d3f 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/AbstractLeadedComponent.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/AbstractLeadedComponent.java @@ -441,7 +441,11 @@ public abstract class AbstractLeadedComponent extends AbstractLabeledComponen stroke = ObjectCache.getInstance().fetchStroke(thickness, new float[] {thickness / 4, thickness * 4}, 0, BasicStroke.CAP_ROUND); break; } - + + Composite oldComposite = g2d.getComposite(); + if (getAlpha() < MAX_ALPHA) { + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * getAlpha() / MAX_ALPHA)); + } if (shouldShadeLeads()) { Shape lineShape = stroke.createStrokedShape(line); @@ -463,6 +467,7 @@ public abstract class AbstractLeadedComponent extends AbstractLabeledComponen if (isCopperArea) observer.stopTrackingContinuityArea(); } + g2d.setComposite(oldComposite); } protected LineStyle getStyle() { diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/boards/AbstractBoard.java b/diylc/diylc-library/src/main/java/org/diylc/components/boards/AbstractBoard.java index e64effa2..8a2d1ddb 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/boards/AbstractBoard.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/boards/AbstractBoard.java @@ -35,7 +35,9 @@ import org.diylc.common.IPlugInPort; import org.diylc.common.ObjectCache; import org.diylc.common.VerticalAlignment; import org.diylc.components.AbstractTransparentComponent; +import org.diylc.core.BoardUndersideDisplay; import org.diylc.core.ComponentState; +import org.diylc.core.IBoard; import org.diylc.core.IDrawingObserver; import org.diylc.core.Project; import org.diylc.core.VisibilityPolicy; @@ -43,9 +45,10 @@ import org.diylc.core.annotations.EditableProperty; import org.diylc.core.measures.Size; import org.diylc.core.measures.SizeUnit; -public abstract class AbstractBoard extends AbstractTransparentComponent { +public abstract class AbstractBoard extends AbstractTransparentComponent implements IBoard { private static final long serialVersionUID = 1L; + public static final Size DEFAULT_UNDERSIDE_OFFSET = new Size(0.1, SizeUnit.in); public static Color BORDER_COLOR = PHENOLIC_COLOR.darker(); public static Color COORDINATE_COLOR = Color.gray.brighter(); @@ -56,7 +59,7 @@ public abstract class AbstractBoard extends AbstractTransparentComponent protected String value = ""; // two control points used for controlling the position protected Point2D[] controlPoints = new Point2D[] {new Point2D.Double(0, 0), - new Point2D.Double(DEFAULT_WIDTH.convertToPixels(), DEFAULT_HEIGHT.convertToPixels())}; + new Point2D.Double(DEFAULT_WIDTH.convertToPixels(), DEFAULT_HEIGHT.convertToPixels())}; // top-left and bottom-right points protected Point2D.Double firstPoint = new Point2D.Double(); protected Point2D.Double secondPoint = new Point2D.Double(); @@ -69,17 +72,20 @@ public abstract class AbstractBoard extends AbstractTransparentComponent protected CoordinateOrigin coordinateOrigin = CoordinateOrigin.Top_Left; protected CoordinateDisplay coordinateDisplay = CoordinateDisplay.One_Side; protected CoordinateType yType = CoordinateType.Letters; - + protected Size length; protected Size width; protected BoardSizingMode mode = BoardSizingMode.TwoPoints; + protected BoardUndersideDisplay boardUndersideDisplay = BoardUndersideDisplay.NONE; + protected Size undersideOffset = DEFAULT_UNDERSIDE_OFFSET; + @Override public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { + IDrawingObserver drawingObserver) { g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); - - Point2D finalSecondPoint = getFinalSecondPoint(); + + Point2D finalSecondPoint = getFinalSecondPoint(); Composite oldComposite = g2d.getComposite(); // render as transparent when dragging @@ -90,64 +96,64 @@ public abstract class AbstractBoard extends AbstractTransparentComponent g2d.setColor(boardColor); g2d.fillRect((int)firstPoint.getX(), (int)firstPoint.getY(), (int)(finalSecondPoint.getX() - firstPoint.getX()), (int)(finalSecondPoint.getY() - firstPoint.getY())); g2d.setComposite(oldComposite); - + // Do not track any changes that follow because the whole board has been // tracked so far. drawingObserver.stopTracking(); g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR - : borderColor); + : borderColor); g2d.drawRect((int)firstPoint.getX(), (int)firstPoint.getY(), (int)(finalSecondPoint.getX() - firstPoint.getX()), (int)(finalSecondPoint.getY() - firstPoint.getY())); } - + protected Point2D getFinalSecondPoint() { Point2D finalSecondPoint; if (getMode() == BoardSizingMode.TwoPoints) finalSecondPoint = secondPoint; else - finalSecondPoint = new Point2D.Double(firstPoint.getX() + getLength().convertToPixels(), - firstPoint.getY() + getWidth().convertToPixels()); + finalSecondPoint = new Point2D.Double(firstPoint.getX() + getLength().convertToPixels(), + firstPoint.getY() + getWidth().convertToPixels()); return finalSecondPoint; } protected void drawCoordinates(Graphics2D g2d, double spacing, Project project) { g2d.setColor(coordinateColor); g2d.setFont(project.getFont().deriveFont(COORDINATE_FONT_SIZE)); - + // The half space is used to do rounding when calculating the range. double halfSpace = spacing / 2; CoordinateOrigin origin = getCoordinateOrigin(); - + Point2D finalSecondPoint = getFinalSecondPoint(); - + if (getCoordinateDisplay() != CoordinateDisplay.None) { int range; double yOffset; CoordinateType yType = getyType(); double y = firstPoint.getY(); - + if (origin == CoordinateOrigin.Top_Left || origin == CoordinateOrigin.Top_Right) { - range = (int) ((finalSecondPoint.getY() - firstPoint.getY() + halfSpace) / spacing); - yOffset = spacing; + range = (int) ((finalSecondPoint.getY() - firstPoint.getY() + halfSpace) / spacing); + yOffset = spacing; } else { - range = (int) ((finalSecondPoint.getY() - firstPoint.getY() + halfSpace) / spacing); - yOffset = -spacing; - y = finalSecondPoint.getY(); + range = (int) ((finalSecondPoint.getY() - firstPoint.getY() + halfSpace) / spacing); + yOffset = -spacing; + y = finalSecondPoint.getY(); } - + for (int c = 1; c < range; c++) { - int xOffset = (yType == CoordinateType.Numbers && c >= 10) || (yType == CoordinateType.Letters && c >= 27) ? 0 : 2; - String label = yType == CoordinateType.Letters ? getCoordinateLabel(c) : Integer.toString(c); - - y += yOffset; - - StringUtils.drawCenteredText(g2d, label, - firstPoint.getX() + xOffset, y, - HorizontalAlignment.LEFT, VerticalAlignment.CENTER); - if (getCoordinateDisplay() == CoordinateDisplay.Both_Sides) { - StringUtils.drawCenteredText(g2d, label, - finalSecondPoint.getX() - xOffset, y, - HorizontalAlignment.RIGHT, VerticalAlignment.CENTER); - } + int xOffset = (yType == CoordinateType.Numbers && c >= 10) || (yType == CoordinateType.Letters && c >= 27) ? 0 : 2; + String label = yType == CoordinateType.Letters ? getCoordinateLabel(c) : Integer.toString(c); + + y += yOffset; + + StringUtils.drawCenteredText(g2d, label, + firstPoint.getX() + xOffset, y, + HorizontalAlignment.LEFT, VerticalAlignment.CENTER); + if (getCoordinateDisplay() == CoordinateDisplay.Both_Sides) { + StringUtils.drawCenteredText(g2d, label, + finalSecondPoint.getX() - xOffset, y, + HorizontalAlignment.RIGHT, VerticalAlignment.CENTER); + } } } @@ -155,8 +161,8 @@ public abstract class AbstractBoard extends AbstractTransparentComponent int range; double xOffset; CoordinateType xType = getxType(); - double x = firstPoint.getX(); - + double x = firstPoint.getX(); + if (origin == CoordinateOrigin.Top_Left || origin == CoordinateOrigin.Bottom_Left) { range = (int) ((finalSecondPoint.getX() - firstPoint.getX() + halfSpace) / spacing); xOffset = spacing; @@ -165,19 +171,19 @@ public abstract class AbstractBoard extends AbstractTransparentComponent xOffset = -spacing; x = finalSecondPoint.getX(); } - + for (int c = 1; c < range; c++) { String label = xType == CoordinateType.Letters ? getCoordinateLabel(c) : Integer.toString(c); - + x += xOffset; - - StringUtils.drawCenteredText(g2d, label, - x, firstPoint.getY() + 2, - HorizontalAlignment.CENTER, VerticalAlignment.BOTTOM); + + StringUtils.drawCenteredText(g2d, label, + x, firstPoint.getY() + 2, + HorizontalAlignment.CENTER, VerticalAlignment.BOTTOM); if (getCoordinateDisplay() == CoordinateDisplay.Both_Sides) { - StringUtils.drawCenteredText(g2d, label, - x, (int) (finalSecondPoint.getY() - COORDINATE_FONT_SIZE), - HorizontalAlignment.CENTER, VerticalAlignment.BOTTOM); + StringUtils.drawCenteredText(g2d, label, + x, (int) (finalSecondPoint.getY() - COORDINATE_FONT_SIZE), + HorizontalAlignment.CENTER, VerticalAlignment.BOTTOM); } } } @@ -225,7 +231,7 @@ public abstract class AbstractBoard extends AbstractTransparentComponent public void setBorderColor(Color borderColor) { this.borderColor = borderColor; } - + @EditableProperty(name = "X") public CoordinateType getxType() { if (xType == null) @@ -250,15 +256,15 @@ public abstract class AbstractBoard extends AbstractTransparentComponent @EditableProperty(name = "Coordinate Origin") public CoordinateOrigin getCoordinateOrigin() { - if (coordinateOrigin == null) - coordinateOrigin = CoordinateOrigin.Top_Left; - return coordinateOrigin; + if (coordinateOrigin == null) + coordinateOrigin = CoordinateOrigin.Top_Left; + return coordinateOrigin; } - + public void setCoordinateOrigin(CoordinateOrigin coordinateOrigin) { - this.coordinateOrigin = coordinateOrigin; + this.coordinateOrigin = coordinateOrigin; } - + @EditableProperty(name = "Y") public CoordinateType getyType() { if (yType == null) @@ -294,9 +300,9 @@ public abstract class AbstractBoard extends AbstractTransparentComponent public void setControlPoint(Point2D point, int index) { controlPoints[index].setLocation(point); firstPoint.setLocation(Math.min(controlPoints[0].getX(), controlPoints[1].getX()), - Math.min(controlPoints[0].getY(), controlPoints[1].getY())); + Math.min(controlPoints[0].getY(), controlPoints[1].getY())); secondPoint.setLocation(Math.max(controlPoints[0].getX(), controlPoints[1].getX()), - Math.max(controlPoints[0].getY(), controlPoints[1].getY())); + Math.max(controlPoints[0].getY(), controlPoints[1].getY())); } @EditableProperty @@ -309,13 +315,13 @@ public abstract class AbstractBoard extends AbstractTransparentComponent public void setValue(String value) { this.value = value; } - + private SizeUnit getDefaultUnit() { if (ConfigurationManager.getInstance().readBoolean(IPlugInPort.METRIC_KEY, true)) return SizeUnit.mm; - return SizeUnit.in; + return SizeUnit.in; } - + @EditableProperty(name = "Explicit Length", validatorClass = BoardModeValidator.class) public Size getLength() { if (getMode() == BoardSizingMode.TwoPoints) { @@ -327,12 +333,12 @@ public abstract class AbstractBoard extends AbstractTransparentComponent public void setLength(Size length) { if (getMode() == BoardSizingMode.Explicit && length != null && width != null) { - setControlPoint(firstPoint, 0); + setControlPoint(firstPoint, 0); Point2D second = new Point2D.Double(firstPoint.getX() + length.convertToPixels(), - firstPoint.getY() + width.convertToPixels()); - setControlPoint(second, 1); + firstPoint.getY() + width.convertToPixels()); + setControlPoint(second, 1); } - this.length = length; + this.length = length; } @EditableProperty(name = "Explicit Width", validatorClass = BoardModeValidator.class) @@ -352,7 +358,7 @@ public abstract class AbstractBoard extends AbstractTransparentComponent } this.width = width; } - + @EditableProperty(name = "Dimension Mode") public BoardSizingMode getMode() { if (mode == null) @@ -363,27 +369,66 @@ public abstract class AbstractBoard extends AbstractTransparentComponent public void setMode(BoardSizingMode mode) { this.mode = mode; } - + + @EditableProperty(name = "Underside Display") + @Override + public BoardUndersideDisplay getBoardUndersideDisplay() { + if (this.boardUndersideDisplay == null) { + this.boardUndersideDisplay = BoardUndersideDisplay.NONE; + } + return this.boardUndersideDisplay; + } + + public void setBoardUndersideDisplay(BoardUndersideDisplay boardUndersideDisplay) { + this.boardUndersideDisplay = boardUndersideDisplay; + } + + @EditableProperty(name = "Underside Offset") + @Override + public Size getUndersideOffset() { + if (undersideOffset == null) { + undersideOffset = DEFAULT_UNDERSIDE_OFFSET; + } + return undersideOffset; + } + + public void setUndersideOffset(Size undersideOffset) { + this.undersideOffset = undersideOffset; + } + + @Override + public Rectangle2D getBoardRectangle() { + Point2D finalSecondPoint = getFinalSecondPoint(); + + return new Rectangle2D.Double(firstPoint.getX(), firstPoint.getY(), + finalSecondPoint.getX() - firstPoint.getX(), finalSecondPoint.getY() - firstPoint.getY()); + } + + @Override + public boolean shouldExportToGerber() { + return false; + } + @Override public Rectangle2D getCachingBounds() { - Point2D finalSecondPoint = getFinalSecondPoint(); - return new Rectangle2D.Double(Math.min(firstPoint.getX(), finalSecondPoint.getX()) - 2, Math.min(firstPoint.getY(), finalSecondPoint.getY()) - 2, - Math.abs(finalSecondPoint.getX() - firstPoint.getX()) + 4, Math.abs(finalSecondPoint.getY() - firstPoint.getY()) + 4); + Point2D finalSecondPoint = getFinalSecondPoint(); + return new Rectangle2D.Double(Math.min(firstPoint.getX(), finalSecondPoint.getX()) - 2, Math.min(firstPoint.getY(), finalSecondPoint.getY()) - 2, + Math.abs(finalSecondPoint.getX() - firstPoint.getX()) + 4, Math.abs(finalSecondPoint.getY() - firstPoint.getY()) + 4); } public static enum CoordinateType { Letters, Numbers } - + public static enum CoordinateDisplay { None, One_Side, Both_Sides; - + @Override public String toString() { return super.toString().replace('_', ' '); }; } - + public static enum CoordinateOrigin { Top_Left, Top_Right, Bottom_Right, Bottom_Left; @@ -392,19 +437,19 @@ public abstract class AbstractBoard extends AbstractTransparentComponent return super.toString().replace('_', ' '); }; } - + public static enum BoardSizingMode { TwoPoints("Opposing Points"), Explicit("Explicit Dimensions"); - + private String label; private BoardSizingMode(String label) { this.label = label; } - + @Override public String toString() { return label; } - } -} + } +} \ No newline at end of file diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/boards/BlankBoard.java b/diylc/diylc-library/src/main/java/org/diylc/components/boards/BlankBoard.java index 5fda6b2c..2cbbe0be 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/boards/BlankBoard.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/boards/BlankBoard.java @@ -38,12 +38,11 @@ import org.diylc.core.Project; import org.diylc.core.annotations.BomPolicy; import org.diylc.core.annotations.ComponentDescriptor; import org.diylc.core.annotations.EditableProperty; -import org.diylc.core.gerber.IGerberBoard; @ComponentDescriptor(name = "Blank Board", category = "Boards", author = "Branislav Stojkovic", - zOrder = IDIYComponent.BOARD, instanceNamePrefix = "Board", description = "Blank circuit board", - bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, autoEdit = false, transformer = SimpleComponentTransformer.class) -public class BlankBoard extends AbstractBoard implements IGerberBoard { + zOrder = IDIYComponent.BOARD, instanceNamePrefix = "Board", description = "Blank circuit board", + bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, autoEdit = false, transformer = SimpleComponentTransformer.class) +public class BlankBoard extends AbstractBoard { private static final long serialVersionUID = 1L; @@ -60,14 +59,14 @@ public class BlankBoard extends AbstractBoard implements IGerberBoard { @Override public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - Point2D finalSecondPoint = getFinalSecondPoint(); - + IDrawingObserver drawingObserver) { + Point2D finalSecondPoint = getFinalSecondPoint(); + Shape clip = g2d.getClip(); if (checkPointsClipped(clip) && !clip.contains(firstPoint.getX(), finalSecondPoint.getY()) - && !clip.contains(finalSecondPoint.getX(), firstPoint.getY())) { + && !clip.contains(finalSecondPoint.getX(), firstPoint.getY())) { return; - } + } g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); if (componentState != ComponentState.DRAGGING) { @@ -86,13 +85,13 @@ public class BlankBoard extends AbstractBoard implements IGerberBoard { // tracked so far. drawingObserver.stopTracking(); g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR - : borderColor); + : borderColor); if (getType() == Type.SQUARE) g2d.drawRect((int)firstPoint.getX(), (int)firstPoint.getY(), (int)(finalSecondPoint.getX() - firstPoint.getX()), (int)(finalSecondPoint.getY() - firstPoint.getY())); else g2d.drawOval((int)firstPoint.getX(), (int)firstPoint.getY(), (int)(finalSecondPoint.getX() - firstPoint.getX()), (int)(finalSecondPoint.getY() - firstPoint.getY())); } - + @Override public CoordinateType getxType() { // Override to prevent editing. @@ -128,12 +127,17 @@ public class BlankBoard extends AbstractBoard implements IGerberBoard { public void setType(Type type) { this.type = type; } - + @Override public String getControlPointNodeName(int index) { return null; } + @Override + public boolean shouldExportToGerber() { + return true; + } + static enum Type { ROUND, SQUARE; @@ -142,12 +146,4 @@ public class BlankBoard extends AbstractBoard implements IGerberBoard { return name().substring(0, 1) + name().substring(1).toLowerCase(); } } - - @Override - public Rectangle2D getBoardRectangle() { - Point2D finalSecondPoint = getFinalSecondPoint(); - - return new Rectangle2D.Double(firstPoint.getX(), firstPoint.getY(), - finalSecondPoint.getX() - firstPoint.getX(), finalSecondPoint.getY() - firstPoint.getY()); - } -} +} \ No newline at end of file diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/CopperTrace.java b/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/CopperTrace.java index baff2381..f0862538 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/CopperTrace.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/CopperTrace.java @@ -133,11 +133,6 @@ public class CopperTrace extends AbstractLeadedComponent implements ILayer return super.getBorderColor(); } - @Override - public Byte getAlpha() { - return super.getAlpha(); - } - @Override public Size getLength() { return super.getLength(); diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/CurvedTrace.java b/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/CurvedTrace.java index 56a3608a..0b35f1df 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/CurvedTrace.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/CurvedTrace.java @@ -111,11 +111,6 @@ public class CurvedTrace extends AbstractCurvedComponent implements ILayer @Override public void setValue(Void value) {} - @Override - public Byte getAlpha() { - return super.getAlpha(); - } - @Override public void setAlpha(Byte alpha) { super.setAlpha(alpha); diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/Eyelet.java b/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/Eyelet.java index c202a7db..3e74d70c 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/Eyelet.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/Eyelet.java @@ -21,13 +21,13 @@ */ package org.diylc.components.connectivity; -import java.awt.Color; -import java.awt.Graphics2D; +import java.awt.*; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import org.diylc.common.ObjectCache; import org.diylc.components.AbstractComponent; +import org.diylc.components.AbstractTransparentComponent; import org.diylc.components.transform.SimpleComponentTransformer; import org.diylc.core.ComponentState; import org.diylc.core.IDIYComponent; @@ -49,7 +49,7 @@ import org.diylc.utils.Constants; zOrder = IDIYComponent.TRACE + 0.1, bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, autoEdit = false, keywordPolicy = KeywordPolicy.SHOW_TYPE_NAME, transformer = SimpleComponentTransformer.class, enableCache = true) -public class Eyelet extends AbstractComponent { +public class Eyelet extends AbstractTransparentComponent { private static final long serialVersionUID = 1L; @@ -71,6 +71,12 @@ public class Eyelet extends AbstractComponent { } int diameter = getClosestOdd((int) size.convertToPixels()); int holeDiameter = getClosestOdd((int) holeSize.convertToPixels()); + + Composite oldComposite = g2d.getComposite(); + if (getAlpha() < MAX_ALPHA) { + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * getAlpha() / MAX_ALPHA)); + } + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1f)); g2d.setColor(color); drawingObserver.startTrackingContinuityArea(true); @@ -84,6 +90,8 @@ public class Eyelet extends AbstractComponent { g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR : color.darker()); g2d.drawOval((int)(point.getX() - holeDiameter / 2), (int)(point.getY() - holeDiameter / 2), holeDiameter, holeDiameter); + + g2d.setComposite(oldComposite); } @Override diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/GroundFill.java b/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/GroundFill.java index 0db6d4ac..ac6d255f 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/GroundFill.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/GroundFill.java @@ -21,8 +21,7 @@ */ package org.diylc.components.connectivity; -import java.awt.Color; -import java.awt.Graphics2D; +import java.awt.*; import java.awt.geom.Point2D; import java.util.Arrays; import java.util.EnumSet; @@ -33,6 +32,7 @@ import com.bancika.gerberwriter.GerberFunctions; import org.diylc.common.ObjectCache; import org.diylc.common.PCBLayer; import org.diylc.components.AbstractComponent; +import org.diylc.components.AbstractTransparentComponent; import org.diylc.components.transform.SimpleComponentTransformer; import org.diylc.core.ComponentState; import org.diylc.core.IDIYComponent; @@ -52,7 +52,8 @@ import org.diylc.core.measures.SizeUnit; @ComponentDescriptor(name = "Ground Fill", author = "Branislav Stojkovic", category = "Connectivity", instanceNamePrefix = "GF", description = "Polygonal ground fill area", zOrder = IDIYComponent.TRACE, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false, transformer = SimpleComponentTransformer.class) -public class GroundFill extends AbstractComponent implements ILayeredComponent, IGerberComponentSimple { +public class GroundFill extends AbstractTransparentComponent + implements ILayeredComponent, IGerberComponentSimple { private static final long serialVersionUID = 1L; @@ -83,7 +84,12 @@ public class GroundFill extends AbstractComponent implements ILayeredCompo yPoints[i] = (int)controlPoints[i].getY(); } drawingObserver.startTrackingContinuityArea(true); + Composite oldComposite = g2d.getComposite(); + if (getAlpha() < MAX_ALPHA) { + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * getAlpha() / MAX_ALPHA)); + } g2d.fillPolygon(xPoints, yPoints, controlPoints.length); + g2d.setComposite(oldComposite); drawingObserver.stopTrackingContinuityArea(); // Do not track any changes that follow because the whole board has been // tracked so far. diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/Jumper.java b/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/Jumper.java index 2f69dd61..61d281cf 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/Jumper.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/Jumper.java @@ -103,11 +103,6 @@ public class Jumper extends AbstractLeadedComponent implements IContinuity return super.getBorderColor(); } - @Override - public Byte getAlpha() { - return super.getAlpha(); - } - @Override public Size getLength() { return super.getLength(); diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/Line.java b/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/Line.java index 0b0234d2..9da327a5 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/Line.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/Line.java @@ -233,11 +233,6 @@ public class Line extends AbstractLeadedComponent { return super.getBorderColor(); } - @Override - public Byte getAlpha() { - return super.getAlpha(); - } - @Override public Size getLength() { return super.getLength(); diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/SolderPad.java b/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/SolderPad.java index e734cca6..ebd05240 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/SolderPad.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/SolderPad.java @@ -17,8 +17,7 @@ */ package org.diylc.components.connectivity; -import java.awt.Color; -import java.awt.Graphics2D; +import java.awt.*; import java.awt.geom.Ellipse2D; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; @@ -29,6 +28,7 @@ import com.bancika.gerberwriter.GerberFunctions; import org.diylc.common.PCBLayer; import org.diylc.components.AbstractComponent; +import org.diylc.components.AbstractTransparentComponent; import org.diylc.components.transform.SimpleComponentTransformer; import org.diylc.core.ComponentState; import org.diylc.core.IDIYComponent; @@ -55,7 +55,8 @@ import org.diylc.utils.Constants; zOrder = IDIYComponent.TRACE + 0.1, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false, keywordPolicy = KeywordPolicy.SHOW_TAG, keywordTag = "PCB", transformer = SimpleComponentTransformer.class, enableCache = true) -public class SolderPad extends AbstractComponent implements ILayeredComponent, IGerberComponentCustom { +public class SolderPad extends AbstractTransparentComponent + implements ILayeredComponent, IGerberComponentCustom { private static final long serialVersionUID = 1L; @@ -90,6 +91,11 @@ public class SolderPad extends AbstractComponent implements ILayeredCompon gerberDrawingObserver.startGerberOutput(gerberCopperLayer, GerberFunctions.CONNECTOR_PAD, false); gerberDrawingObserver.startGerberOutput(org.diylc.core.gerber.GerberLayer.SolderMaskBot, "Material", false); } + Composite oldComposite = g2d.getComposite(); + if (getAlpha() < MAX_ALPHA) { + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * getAlpha() / MAX_ALPHA)); + } + if (type == Type.ROUND) { g2d.fill(new Ellipse2D.Double(point.getX() - diameter / 2, point.getY() - diameter / 2, diameter, diameter)); @@ -116,6 +122,7 @@ public class SolderPad extends AbstractComponent implements ILayeredCompon g2d.fill(new Ellipse2D.Double(point.getX() - holeDiameter / 2, point.getY() - holeDiameter / 2, holeDiameter, holeDiameter)); } + g2d.setComposite(oldComposite); if (gerberDrawingObserver != null) gerberDrawingObserver.stopGerberOutput(); } diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/TraceCut.java b/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/TraceCut.java index 3bc979a3..4cc3964f 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/TraceCut.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/TraceCut.java @@ -21,14 +21,14 @@ */ package org.diylc.components.connectivity; -import java.awt.Color; -import java.awt.Graphics2D; +import java.awt.*; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import org.diylc.common.ObjectCache; import org.diylc.common.OrientationHV; import org.diylc.components.AbstractComponent; +import org.diylc.components.AbstractTransparentComponent; import org.diylc.components.boards.AbstractBoard; import org.diylc.components.boards.VeroBoard; import org.diylc.components.transform.SimpleComponentTransformer; @@ -49,7 +49,7 @@ import org.diylc.utils.Constants; description = "Designates the place where a trace on the vero board needs to be cut", instanceNamePrefix = "Cut", zOrder = IDIYComponent.BOARD + 1, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false, transformer = SimpleComponentTransformer.class, enableCache = true) -public class TraceCut extends AbstractComponent implements ILayeredComponent { +public class TraceCut extends AbstractTransparentComponent implements ILayeredComponent { private static final long serialVersionUID = 1L; @@ -79,6 +79,10 @@ public class TraceCut extends AbstractComponent implements ILayeredCompone if (checkPointsClipped(g2d.getClip())) { return; } + Composite oldComposite = g2d.getComposite(); + if (getAlpha() < MAX_ALPHA) { + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * getAlpha() / MAX_ALPHA)); + } g2d.setStroke(ObjectCache.getInstance().fetchZoomableStroke(1f)); int size = getClosestOdd((int) this.size.convertToPixels()); int cutWidth = getClosestOdd((int) CUT_WIDTH.convertToPixels()); @@ -105,6 +109,7 @@ public class TraceCut extends AbstractComponent implements ILayeredCompone g2d.setColor(getBoardColor().darker()); g2d.drawOval((int)(point.getX() - holeSize / 2), (int)(point.getY() - holeSize / 2), holeSize, holeSize); } + g2d.setComposite(oldComposite); } @Override diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/Turret.java b/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/Turret.java index bd5c21f7..9400d75c 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/Turret.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/Turret.java @@ -21,13 +21,13 @@ */ package org.diylc.components.connectivity; -import java.awt.Color; -import java.awt.Graphics2D; +import java.awt.*; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import org.diylc.common.ObjectCache; import org.diylc.components.AbstractComponent; +import org.diylc.components.AbstractTransparentComponent; import org.diylc.components.transform.SimpleComponentTransformer; import org.diylc.core.ComponentState; import org.diylc.core.IDIYComponent; @@ -47,7 +47,7 @@ import org.diylc.utils.Constants; zOrder = IDIYComponent.TRACE + 0.1, bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, autoEdit = false, keywordPolicy = KeywordPolicy.SHOW_TYPE_NAME, transformer = SimpleComponentTransformer.class, enableCache = true) -public class Turret extends AbstractComponent { +public class Turret extends AbstractTransparentComponent { private static final long serialVersionUID = 1L; @@ -67,6 +67,10 @@ public class Turret extends AbstractComponent { if (checkPointsClipped(g2d.getClip())) { return; } + Composite oldComposite = g2d.getComposite(); + if (getAlpha() < MAX_ALPHA) { + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * getAlpha() / MAX_ALPHA)); + } int diameter = getClosestOdd((int) size.convertToPixels()); int holeDiameter = getClosestOdd((int) holeSize.convertToPixels()); g2d.setColor(color); @@ -82,6 +86,7 @@ public class Turret extends AbstractComponent { g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR : color.darker()); g2d.drawOval((int)(point.getX() - holeDiameter / 2), (int)(point.getY() - holeDiameter / 2), holeDiameter, holeDiameter); + g2d.setComposite(oldComposite); } @Override diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/guitar/Freeway3x3_03.java b/diylc/diylc-library/src/main/java/org/diylc/components/guitar/Freeway3x3_03.java index 253ae23d..142b4499 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/guitar/Freeway3x3_03.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/guitar/Freeway3x3_03.java @@ -304,7 +304,8 @@ public class Freeway3x3_03 extends AbstractTransparentComponent implements if (svgDiagram == null) { try { byte[] data = - IOUtils.toByteArray(Freeway3x3_03.class.getResourceAsStream("/freeway_3x3-03.svg")); + IOUtils.toByteArray(Freeway3x3_03.class.getResourceAsStream( + "/component-drawings/freeway_3x3-03.svg")); ByteArrayInputStream bis = new ByteArrayInputStream(data); SVGUniverse universe = new SVGUniverse(); URI url = universe.loadSVG(bis, diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/misc/Image.java b/diylc/diylc-library/src/main/java/org/diylc/components/misc/Image.java index 1e67dd13..2527a4cc 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/misc/Image.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/misc/Image.java @@ -40,7 +40,6 @@ import org.diylc.awt.ImageUtils; import org.diylc.common.ObjectCache; import org.diylc.common.Orientation; import org.diylc.components.AbstractTransparentComponent; -import org.diylc.components.boards.AbstractBoard; import org.diylc.components.transform.ImageTransformer; import org.diylc.core.ComponentState; import org.diylc.core.IDIYComponent; @@ -72,7 +71,7 @@ public class Image extends AbstractTransparentComponent { private Orientation orientation; static { - String name = "/image.png"; + String name = "/diylc-library-images/image.png"; try (InputStream inputStream = Image.class.getResourceAsStream(name)) { if (inputStream != null) { ICON = new ImageIcon(inputStream.readAllBytes(), name); @@ -99,7 +98,7 @@ public class Image extends AbstractTransparentComponent { public Image() { try { - data = IOUtils.toByteArray(Image.class.getResourceAsStream("/image.png")); + data = IOUtils.toByteArray(Image.class.getResourceAsStream("/diylc-library-images/image.png")); } catch (IOException e) { e.printStackTrace(); } diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/misc/SVGImage.java b/diylc/diylc-library/src/main/java/org/diylc/components/misc/SVGImage.java index 91610df6..739d16f0 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/misc/SVGImage.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/misc/SVGImage.java @@ -81,7 +81,8 @@ public class SVGImage extends AbstractTransparentComponent { public SVGImage() { try { - data = IOUtils.toByteArray(SVGImage.class.getResourceAsStream("/diylc.svg")); + data = IOUtils.toByteArray(SVGImage.class.getResourceAsStream( + "/diylc-library-images/diylc.svg")); } catch (IOException e) { e.printStackTrace(); } diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/transform/CliffJackTransformer.java b/diylc/diylc-library/src/main/java/org/diylc/components/transform/CliffJackTransformer.java index 816f668d..687545e1 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/transform/CliffJackTransformer.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/transform/CliffJackTransformer.java @@ -43,7 +43,7 @@ public class CliffJackTransformer implements IComponentTransformer { @Override public boolean mirroringChangesCircuit() { - return true; + return false; } @Override diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/transform/MiniToggleSwitchTransformer.java b/diylc/diylc-library/src/main/java/org/diylc/components/transform/MiniToggleSwitchTransformer.java index 21da24ee..f347f9f2 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/transform/MiniToggleSwitchTransformer.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/transform/MiniToggleSwitchTransformer.java @@ -48,14 +48,26 @@ public class MiniToggleSwitchTransformer implements IComponentTransformer { @Override public void rotate(IDIYComponent component, Point2D center, int direction) { - AffineTransform rotate = AffineTransform.getRotateInstance(Math.PI / 2 * direction, center.getX(), center.getY()); - for (int index = 0; index < component.getControlPointCount(); index++) { - Point2D p = new Point2D.Double(); - rotate.transform(component.getControlPoint(index), p); - component.setControlPoint(p, index); - } - MiniToggleSwitch sw = (MiniToggleSwitch) component; + + // Calculate center of all control points + double sumX = 0, sumY = 0; + for (int i = 0; i < sw.getControlPointCount(); i++) { + Point2D p = sw.getControlPoint(i); + sumX += p.getX(); + sumY += p.getY(); + } + Point2D controlCenter = new Point2D.Double( + sumX / sw.getControlPointCount(), + sumY / sw.getControlPointCount() + ); + + // Calculate where control center should end up after rotation + Point2D targetCenter = new Point2D.Double(); + AffineTransform rotate = AffineTransform.getRotateInstance(Math.PI / 2 * direction, center.getX(), center.getY()); + rotate.transform(controlCenter, targetCenter); + + // Update orientation first - this will rotate points around first point OrientationHV o = sw.getOrientation(); int oValue = o.ordinal(); oValue += direction; @@ -65,6 +77,29 @@ public class MiniToggleSwitchTransformer implements IComponentTransformer { oValue = 0; o = OrientationHV.values()[oValue]; sw.setOrientation(o); + + // Recalculate current control center after orientation change + sumX = 0; + sumY = 0; + for (int i = 0; i < sw.getControlPointCount(); i++) { + Point2D p = sw.getControlPoint(i); + sumX += p.getX(); + sumY += p.getY(); + } + Point2D newControlCenter = new Point2D.Double( + sumX / sw.getControlPointCount(), + sumY / sw.getControlPointCount() + ); + + // Calculate and apply translation to move control center to target position + double dx = targetCenter.getX() - newControlCenter.getX(); + double dy = targetCenter.getY() - newControlCenter.getY(); + + // Apply translation to all points + for (int i = 0; i < sw.getControlPointCount(); i++) { + Point2D p = sw.getControlPoint(i); + sw.setControlPoint(new Point2D.Double(p.getX() + dx, p.getY() + dy), i); + } } @Override diff --git a/diylc/diylc-library/src/main/resources/freeway_3x3-03.svg b/diylc/diylc-library/src/main/resources/component-drawings/freeway_3x3-03.svg similarity index 100% rename from diylc/diylc-library/src/main/resources/freeway_3x3-03.svg rename to diylc/diylc-library/src/main/resources/component-drawings/freeway_3x3-03.svg diff --git a/diylc/diylc-library/src/main/resources/AxialElectrolyticCapacitor.datasheet b/diylc/diylc-library/src/main/resources/datasheets/AxialElectrolyticCapacitor.datasheet similarity index 100% rename from diylc/diylc-library/src/main/resources/AxialElectrolyticCapacitor.datasheet rename to diylc/diylc-library/src/main/resources/datasheets/AxialElectrolyticCapacitor.datasheet diff --git a/diylc/diylc-library/src/main/resources/AxialFilmCapacitor.datasheet b/diylc/diylc-library/src/main/resources/datasheets/AxialFilmCapacitor.datasheet similarity index 100% rename from diylc/diylc-library/src/main/resources/AxialFilmCapacitor.datasheet rename to diylc/diylc-library/src/main/resources/datasheets/AxialFilmCapacitor.datasheet diff --git a/diylc/diylc-library/src/main/resources/RadialElectrolytic.datasheet b/diylc/diylc-library/src/main/resources/datasheets/RadialElectrolytic.datasheet similarity index 100% rename from diylc/diylc-library/src/main/resources/RadialElectrolytic.datasheet rename to diylc/diylc-library/src/main/resources/datasheets/RadialElectrolytic.datasheet diff --git a/diylc/diylc-library/src/main/resources/RadialFilmCapacitor.datasheet b/diylc/diylc-library/src/main/resources/datasheets/RadialFilmCapacitor.datasheet similarity index 100% rename from diylc/diylc-library/src/main/resources/RadialFilmCapacitor.datasheet rename to diylc/diylc-library/src/main/resources/datasheets/RadialFilmCapacitor.datasheet diff --git a/diylc/diylc-library/src/main/resources/RadialMicaCapacitor.datasheet b/diylc/diylc-library/src/main/resources/datasheets/RadialMicaCapacitor.datasheet similarity index 100% rename from diylc/diylc-library/src/main/resources/RadialMicaCapacitor.datasheet rename to diylc/diylc-library/src/main/resources/datasheets/RadialMicaCapacitor.datasheet diff --git a/diylc/diylc-library/src/main/resources/diylc.svg b/diylc/diylc-library/src/main/resources/diylc-library-images/diylc.svg similarity index 100% rename from diylc/diylc-library/src/main/resources/diylc.svg rename to diylc/diylc-library/src/main/resources/diylc-library-images/diylc.svg diff --git a/diylc/diylc-library/src/main/resources/image.png b/diylc/diylc-library/src/main/resources/diylc-library-images/image.png similarity index 100% rename from diylc/diylc-library/src/main/resources/image.png rename to diylc/diylc-library/src/main/resources/diylc-library-images/image.png diff --git a/diylc/diylc-swing/.classpath b/diylc/diylc-swing/.classpath deleted file mode 100644 index cd173d6f..00000000 --- a/diylc/diylc-swing/.classpath +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/diylc/diylc-swing/.project b/diylc/diylc-swing/.project deleted file mode 100644 index 33001697..00000000 --- a/diylc/diylc-swing/.project +++ /dev/null @@ -1,34 +0,0 @@ - - - diylc-swing - - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.eclipse.m2e.core.maven2Builder - - - - - - org.eclipse.m2e.core.maven2Nature - org.eclipse.jdt.core.javanature - - - - 1741597247368 - - 30 - - org.eclipse.core.resources.regexFilterMatcher - node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ - - - - diff --git a/diylc/diylc-swing/deploy/linux/appimage/diylc.sh b/diylc/diylc-swing/deploy/linux/appimage/diylc.sh index 07214765..1f2138b2 100644 --- a/diylc/diylc-swing/deploy/linux/appimage/diylc.sh +++ b/diylc/diylc-swing/deploy/linux/appimage/diylc.sh @@ -1,26 +1,25 @@ #!/bin/bash #set -x # Enable debug mode -HERE="$(dirname "$(readlink -f "$0")")" +# Get the AppImage directory +if [ -n "$APPDIR" ]; then + HERE="$APPDIR/usr/bin" +else + HERE="$(cd "$(dirname "$0")" && pwd)" +fi + echo "diylc.sh: Running from directory: $HERE" -# Check if Java is available -if [ -d "$HERE/jre" ]; then - export JAVA_HOME="$HERE/jre" - export PATH="$JAVA_HOME/bin:$PATH" - JAVA="$JAVA_HOME/bin/java" - echo "diylc.sh: Using bundled JRE: $JAVA" -else - JAVA="$(which java)" - echo "diylc.sh: Using system Java: $JAVA" -fi - -# Debug: Check Java existence -if [ ! -x "$JAVA" ]; then - echo "diylc.sh: ERROR - Java binary not found or not executable!" +# Use system Java +JAVA="$(which java)" +if [ -z "$JAVA" ] || [ ! -x "$JAVA" ]; then + echo "diylc.sh: ERROR - System Java not found or not executable!" + echo "diylc.sh: Please install Java 17 or later" exit 1 fi +echo "diylc.sh: Using system Java: $JAVA" + cd "$HERE" echo "diylc.sh: Current working directory: $(pwd)" @@ -28,11 +27,9 @@ echo "diylc.sh: Current working directory: $(pwd)" echo "diylc.sh: Executing DIYLCStarter with Java" exec "$JAVA" \ - -Xms512m \ + -Xms1024m \ -Xmx4096m \ - -cp "$HERE/../lib/diylc.jar" \ - --add-exports java.desktop/com.apple.eawt.event=ALL-UNNAMED \ - --add-exports java.desktop/com.apple.eio=ALL-UNNAMED \ + -cp "$APPDIR/usr/lib/diylc.jar" \ --add-opens java.base/java.util=ALL-UNNAMED \ --add-opens java.base/java.lang=ALL-UNNAMED \ --add-opens java.base/java.text=ALL-UNNAMED \ diff --git a/diylc/diylc-swing/deploy/linux/run.sh b/diylc/diylc-swing/deploy/linux/run.sh index 7f78069a..943efe7f 100755 --- a/diylc/diylc-swing/deploy/linux/run.sh +++ b/diylc/diylc-swing/deploy/linux/run.sh @@ -2,4 +2,19 @@ JAVA_BIN="$(which java)" DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" CLASS_PATH="${DIR}/diylc.jar" -exec java -Xms512m -Xmx4096m -Dorg.diylc.scriptRun=true -Dfile.encoding=UTF-8 -cp "$CLASS_PATH" --add-exports java.desktop/com.apple.eawt.event=ALL-UNNAMED --add-exports java.desktop/com.apple.eio=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.text=ALL-UNNAMED --add-opens java.desktop/java.awt=ALL-UNNAMED --add-opens java.desktop/java.awt.font=ALL-UNNAMED --add-opens java.desktop/java.awt.geom=ALL-UNNAMED org.diylc.DIYLCStarter "$@" \ No newline at end of file + +exec java \ + -Xms1024m \ + -Xmx4096m \ + -Dorg.diylc.scriptRun=true \ + -Dfile.encoding=UTF-8 \ + -cp "$CLASS_PATH" \ + --add-exports java.desktop/com.apple.eawt.event=ALL-UNNAMED \ + --add-exports java.desktop/com.apple.eio=ALL-UNNAMED \ + --add-opens java.base/java.util=ALL-UNNAMED \ + --add-opens java.base/java.lang=ALL-UNNAMED \ + --add-opens java.base/java.text=ALL-UNNAMED \ + --add-opens java.desktop/java.awt=ALL-UNNAMED \ + --add-opens java.desktop/java.awt.font=ALL-UNNAMED \ + --add-opens java.desktop/java.awt.geom=ALL-UNNAMED \ + org.diylc.DIYLCStarter "$@" \ No newline at end of file diff --git a/diylc/diylc-swing/deploy/linux/test-appimage.sh b/diylc/diylc-swing/deploy/linux/test-appimage.sh new file mode 100755 index 00000000..b8de95c5 --- /dev/null +++ b/diylc/diylc-swing/deploy/linux/test-appimage.sh @@ -0,0 +1,72 @@ +#!/bin/bash + +# Build the AppImage +echo "Building AppImage..." +cd ../.. +#mvn clean package -P linux-appimage + +# Check if build was successful +if [ $? -ne 0 ]; then + echo "Build failed!" + exit 1 +fi + +# Get the AppImage path +APPIMAGE="target/DIYLayoutCreator-5.1.0-x86_64.AppImage" +ZIP_FILE="target/diylc-5.1.0-linux.zip" + +# Check if files exist +if [ ! -f "$APPIMAGE" ]; then + echo "AppImage not found at $APPIMAGE" + exit 1 +fi + +if [ ! -f "$ZIP_FILE" ]; then + echo "Zip file not found at $ZIP_FILE" + exit 1 +fi + +# Create test directory +TEST_DIR="target/appimage-test" +rm -rf "$TEST_DIR" +mkdir -p "$TEST_DIR" + +# Copy files to test directory +echo "Copying files to test directory..." +cp "$APPIMAGE" "$TEST_DIR/" +cp "$ZIP_FILE" "$TEST_DIR/" + +# Extract zip file +echo "Extracting zip file..." +cd "$TEST_DIR" +unzip "diylc-5.1.0-linux.zip" + +# Make AppImage executable +chmod +x "DIYLayoutCreator-5.1.0-x86_64.AppImage" + +# Test AppImage structure +echo "Testing AppImage structure..." +if [ -f "DIYLayoutCreator-5.1.0-x86_64.AppImage" ]; then + echo "AppImage file exists and is executable" + echo "AppImage size: $(ls -lh DIYLayoutCreator-5.1.0-x86_64.AppImage | awk '{print $5}')" + echo "AppImage permissions: $(ls -l DIYLayoutCreator-5.1.0-x86_64.AppImage | awk '{print $1}')" + + # Check if AppImage has the correct magic number + if file "DIYLayoutCreator-5.1.0-x86_64.AppImage" | grep -q "ELF 64-bit LSB executable"; then + echo "AppImage has correct ELF format" + else + echo "Warning: AppImage might not have correct ELF format" + fi + + # Check if AppImage has the correct AppImage magic bytes + if dd if="DIYLayoutCreator-5.1.0-x86_64.AppImage" bs=8 count=1 2>/dev/null | grep -q "AI"; then + echo "AppImage has correct AppImage magic bytes" + else + echo "Warning: AppImage might not have correct AppImage magic bytes" + fi + + echo "AppImage structure test completed successfully!" +else + echo "AppImage file not found in test directory!" + exit 1 +fi \ No newline at end of file diff --git a/diylc/diylc-swing/deploy/print_version.sh b/diylc/diylc-swing/deploy/print_version.sh new file mode 100755 index 00000000..2b6cdea0 --- /dev/null +++ b/diylc/diylc-swing/deploy/print_version.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +# Get the directory where this script is located +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +# Set DEBUG environment variable +export DEBUG=true + +# Run the VersionReader class +java -cp "../target/diylc.jar" --add-opens java.base/java.util=ALL-UNNAMED \ + --add-opens java.base/java.lang=ALL-UNNAMED \ + --add-opens java.base/java.text=ALL-UNNAMED \ + --add-opens java.desktop/java.awt=ALL-UNNAMED \ + --add-opens java.desktop/java.awt.font=ALL-UNNAMED \ + --add-opens java.desktop/java.awt.geom=ALL-UNNAMED \ + org.diylc.utils.VersionReader "$SCRIPT_DIR/../" diff --git a/diylc/diylc-swing/deploy/upload_version.sh b/diylc/diylc-swing/deploy/upload_version.sh new file mode 100755 index 00000000..7e2376b8 --- /dev/null +++ b/diylc/diylc-swing/deploy/upload_version.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +# Get the directory where this script is located +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +# FTP settings +FTP_USER="diylc_deploy@diy-fever.com" +FTP_HOST="ftp.diy-fever.com" + +# Check if password is set +if [ -z "$DIYLC_DEPLOY_PWD" ]; then + echo "Error: DIYLC_DEPLOY_PWD environment variable is not set" + exit 1 +fi + +# Source file path +SOURCE_FILE="$SCRIPT_DIR/../../diylc-core/src/main/resources/update.xml" + +# Check if source file exists +if [ ! -f "$SOURCE_FILE" ]; then + echo "Error: update.xml not found at $SOURCE_FILE" + exit 1 +fi + +# Upload using FTP +echo "Uploading update.xml to $FTP_USER@$FTP_HOST..." +ftp -n "$FTP_HOST" << EOF +user $FTP_USER $DIYLC_DEPLOY_PWD +binary +put "$SOURCE_FILE" update.xml +quit +EOF + +# Check FTP exit status +if [ $? -eq 0 ]; then + echo "Upload successful" +else + echo "Upload failed" + exit 1 +fi diff --git a/diylc/diylc-swing/deploy/win/launch4j-x64.xml b/diylc/diylc-swing/deploy/win/launch4j-x64.xml index aa8e8e3a..d2740d62 100644 --- a/diylc/diylc-swing/deploy/win/launch4j-x64.xml +++ b/diylc/diylc-swing/deploy/win/launch4j-x64.xml @@ -24,7 +24,7 @@ true 17 - 512 + 1024 4096 -Dorg.diylc.scriptRun=true -Dfile.encoding=UTF-8 diff --git a/diylc/diylc-swing/dict.txt b/diylc/diylc-swing/dict.txt index ee8cc2d2..712013cd 100644 --- a/diylc/diylc-swing/dict.txt +++ b/diylc/diylc-swing/dict.txt @@ -74,6 +74,7 @@ And Angle Angle Offset Anti-Aliasing +Apply Model Arrow Size Author Auto-Create Pads @@ -85,6 +86,8 @@ Below Board Board Color Board Width +Board1 +Board2 Boards Bobbin 1 Bobbin 2 @@ -588,6 +591,8 @@ Tubular Beveled Two Type Ultra-miniature +Underside Display +Underside Offset Underside Pad Color Underside Trace Color Undo diff --git a/diylc/diylc-swing/pom.xml b/diylc/diylc-swing/pom.xml index 95c2456b..ec9dac10 100644 --- a/diylc/diylc-swing/pom.xml +++ b/diylc/diylc-swing/pom.xml @@ -260,47 +260,6 @@ - - sign-jar-launcher - package - - run - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -328,7 +287,7 @@ single - diylc-${project.version} + diylc-${project.version}-universal false @@ -391,39 +350,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - JAVA_HOME="$APPDIR/usr/lib/jre" - JAVA_HOME="$APPDIR/usr/bin/jre" - - @@ -539,9 +465,17 @@ - + + + + + + + + + - + @@ -703,6 +637,49 @@ + + + sign-jar-launcher + package + + run + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + create-mac-bundle @@ -740,7 +717,7 @@ - + + + sign-jar-launcher + package + + run + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + create-mac-bundle @@ -1011,7 +1031,7 @@ -