mirror of
https://github.com/bancika/diy-layout-creator
synced 2026-11-10 01:02:08 +10:00
Compare commits
312 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bb3b37f23b | |||
| fcea5975a8 | |||
| 2294ac45a2 | |||
| 5598f22b2f | |||
| 812b7adb28 | |||
| 9fd5a8fe96 | |||
| 0b8952e354 | |||
| 5c47ff1ef0 | |||
| b85b93404b | |||
| b46f46aa99 | |||
| 48266d3b27 | |||
| eb6cc76f02 | |||
| a5d512ca37 | |||
| 1d038b5f8c | |||
| 9366f9c602 | |||
| 23b4fcae02 | |||
| 14a994e68f | |||
| 894ff1a2cb | |||
| 78dcd27e1d | |||
| 714db98afa | |||
| 2faa2c6d61 | |||
| 3c45336afe | |||
| a0601cc83d | |||
| 9925d58347 | |||
| 6c241b3180 | |||
| 838adc9a51 | |||
| 41d2b73cca | |||
| 8d3789a0b0 | |||
| 95f65dcdf1 | |||
| 3d0f9554b0 | |||
| 0c21e013b4 | |||
| f8e24b0937 | |||
| 37d5ce18fc | |||
| e9a2785344 | |||
| 4de3b6d97c | |||
| 92a2bb9809 | |||
| 440b953531 | |||
| 1bc11e09ab | |||
| f20b896184 | |||
| 49d93b42a4 | |||
| b279510e5c | |||
| a83cda9ecd | |||
| f63b422a8c | |||
| 7af919b303 | |||
| 1c1ec2fcf5 | |||
| 8ccdd84a6f | |||
| 54ff518438 | |||
| c893b37fdf | |||
| 81e259bb62 | |||
| d5aac6b265 | |||
| d544797047 | |||
| 8ed2c0c9a5 | |||
| 2d1cf515d6 | |||
| 2553ffbba7 | |||
| 04418f8101 | |||
| c548a35939 | |||
| 777f4aa3fd | |||
| c0c226c580 | |||
| 40d234d1c4 | |||
| bc0d759d39 | |||
| b3497cdca8 | |||
| cc0f698c8b | |||
| b0123db3e7 | |||
| c9a32cc390 | |||
| 46d9e1f82a | |||
| 9596d6ca8e | |||
| 65315ed559 | |||
| 57bce6b8e5 | |||
| 403d0ea433 | |||
| 595cfb3ed1 | |||
| 2c689c584d | |||
| 84eaa1bf29 | |||
| 20e01762b8 | |||
| 08aec6fa9b | |||
| f51d19b39a | |||
| 8bfb3ade55 | |||
| 3847813351 | |||
| 67761b1027 | |||
| 7cca8f86b2 | |||
| 39976ec3d6 | |||
| a155aef596 | |||
| b24bfafb39 | |||
| 31ce46f147 | |||
| ce43a5d2e6 | |||
| 0d007e5737 | |||
| c0dac1a1db | |||
| ec7244042d | |||
| 88275e95e2 | |||
| add8566d4f | |||
| c5495ad14f | |||
| 94f1c68c7b | |||
| 3e67515f69 | |||
| 2091b8a03d | |||
| 235acf538f | |||
| 45404aaabd | |||
| 2727276a09 | |||
| cb6aa83269 | |||
| 39daa9e61f | |||
| 8313a62324 | |||
| c1d718a0f9 | |||
| 6e5174750f | |||
| 1cfb30f35e | |||
| ddfc615a6a | |||
| f53ad8c206 | |||
| 20645fed13 | |||
| d3c2e20359 | |||
| 46f693addf | |||
| 008ee8564b | |||
| b234015a32 | |||
| bb69d8dd04 | |||
| b02eaf928d | |||
| 2c4ff547fe | |||
| ca78cd030b | |||
| 51a12d61e1 | |||
| 661e5e2403 | |||
| ae8d015a78 | |||
| 59096d69ed | |||
| 66e1227182 | |||
| 19bdf41655 | |||
| 0acca63ccd | |||
| 6d2e876381 | |||
| 13f13191c4 | |||
| 86500cb4a0 | |||
| f7e5421f18 | |||
| c7bc8360ba | |||
| d91527a91c | |||
| 9e760ba655 | |||
| 9a2585d23f | |||
| 83723dd416 | |||
| 7597143b1b | |||
| 0cb4377830 | |||
| fbf2569a7e | |||
| 290406609b | |||
| 417c389b0a | |||
| 1af44eadfc | |||
| 364010ae63 | |||
| 7fb78237fb | |||
| c120bc10ed | |||
| 9c81ad0eec | |||
| bb564248d9 | |||
| 3deb988a06 | |||
| ae3e698d9e | |||
| 2735d7e343 | |||
| f4cc0ca360 | |||
| 99b7dbb6f3 | |||
| e3ca5244fe | |||
| a0b78a5e3d | |||
| 81b299865c | |||
| 3027753225 | |||
| 13997ee757 | |||
| 8c09fe72e6 | |||
| 6e9169242a | |||
| 91389ef09b | |||
| 921b503057 | |||
| efceedc924 | |||
| cad26211b3 | |||
| 36259bc83b | |||
| 024ede48a8 | |||
| b44c3bad62 | |||
| 0741f4334b | |||
| 46f20a75ec | |||
| 34ea20eedd | |||
| 08a0e451e7 | |||
| 53eb70e693 | |||
| 1b8a72d24a | |||
| 04840bac7b | |||
| 0a97b53f60 | |||
| 4d3f2968c1 | |||
| d5f3457c43 | |||
| 0c76b93db0 | |||
| 197f9ca216 | |||
| c8af6dbbb2 | |||
| 0a444f5ee7 | |||
| f0172f9adc | |||
| 5c9754baf4 | |||
| ef5bde9091 | |||
| a4efb57452 | |||
| 58aa0ab5be | |||
| 32b2713732 | |||
| cb21392d1e | |||
| 149cdbca48 | |||
| 73e4d6fc93 | |||
| 08bc4f5170 | |||
| 813baee504 | |||
| 74e524e98c | |||
| a8f5155acd | |||
| dd06195035 | |||
| 19ea23895b | |||
| 61444db46d | |||
| 54e991891d | |||
| ba735dd350 | |||
| 6b1913fd5b | |||
| c6f6aa9186 | |||
| ef51c44e54 | |||
| 5dc911776c | |||
| 9757e81500 | |||
| 46f8506c39 | |||
| f1ccfa86c0 | |||
| 5b2a9c0e43 | |||
| 81a6cf282b | |||
| 984edc196b | |||
| e5fff0b538 | |||
| 26c3c488e0 | |||
| 62bb6aac05 | |||
| 1a1e8ae56f | |||
| 7a8e25ab39 | |||
| 7b47a747bf | |||
| c4b66f5995 | |||
| 97cc9ca6c8 | |||
| 252b9ef560 | |||
| 77d038cef9 | |||
| 6ce5d305f1 | |||
| 2d0eb136fe | |||
| 4c03d9f658 | |||
| c5c4d6c04e | |||
| c7f468a0bc | |||
| 41b670616c | |||
| f62de41a95 | |||
| e6bdedfaea | |||
| e2e33a1b13 | |||
| 2266dadcba | |||
| 149f05f20c | |||
| 539b3c68de | |||
| 185eb9d1d3 | |||
| 9525505865 | |||
| a91e8dd062 | |||
| 5ce3d6d4b3 | |||
| facf816458 | |||
| afadc5e171 | |||
| a91eb15837 | |||
| cd74e417a9 | |||
| 7ca6eb0e2f | |||
| 78600f1c24 | |||
| 7aa6f31e67 | |||
| e91dc72424 | |||
| f9e2c1f1fa | |||
| bc49daf1be | |||
| dc07d2732b | |||
| 2f76bb8446 | |||
| cc286f9c41 | |||
| 42ca1926e1 | |||
| 007a52f0b5 | |||
| 7caadec1ec | |||
| 0f3f2a350b | |||
| bfe044f3f6 | |||
| 4eda278bc0 | |||
| 3379987a74 | |||
| c6b2cba3aa | |||
| a6538947d0 | |||
| 54e97b9adc | |||
| 4ebd1deed4 | |||
| af2195798f | |||
| c7a04075f4 | |||
| ebf988eaba | |||
| 0cd9f97e70 | |||
| 40d9b296da | |||
| 3f8dee89bb | |||
| 82d265e457 | |||
| 6aa63d3a7b | |||
| fdc76c80cf | |||
| a574eac4e6 | |||
| beb6c4857d | |||
| 8e5b4b0ecc | |||
| a92c6de926 | |||
| e38f4121b9 | |||
| bd40ad7dda | |||
| 767df37286 | |||
| fc33be65ab | |||
| a4639d3f1a | |||
| 405f8367df | |||
| dbf3a1e64d | |||
| 82d5c4436e | |||
| e541026656 | |||
| 8be8c23213 | |||
| 54b0519f09 | |||
| 41a2f3ed78 | |||
| 8dd1b74f96 | |||
| b9613fa72d | |||
| 295504d7d9 | |||
| ea00c503ee | |||
| 162980da67 | |||
| f2cd0f2a56 | |||
| d38d2f9b1b | |||
| 22e59d991c | |||
| 1ffd9b50a8 | |||
| 1268f83f5e | |||
| ce0ac2460c | |||
| e9615d4d64 | |||
| 48a6857738 | |||
| b489adf7c7 | |||
| 1cfe2ee99a | |||
| 9888d5f4c8 | |||
| ac1c68c7c1 | |||
| 4a3304a20e | |||
| f8a9171e12 | |||
| 79abef597b | |||
| 5593804a6f | |||
| abb6fabf39 | |||
| 1566fc07b4 | |||
| b0e986b4f9 | |||
| fb0dc31b98 | |||
| 1188a2e3c6 | |||
| 56a97f28b9 | |||
| 1c36acf6db | |||
| f07fd9c5e6 | |||
| 27a24b45b3 | |||
| c567342aaa | |||
| d9b7dda449 | |||
| 99f2482b39 | |||
| aadc9e394d | |||
| 3fec176fc1 | |||
| 680397b44f |
@@ -0,0 +1,8 @@
|
||||
Thank you for reporting issues and contributing ideas and features to DIYLC repository!
|
||||
|
||||
Before you proceed, please read the following:
|
||||
|
||||
* If you are reporting a bug, please attach the latest application log file together with description of steps that lead to the issue. They can be found in the user directory under `.diylc/logs` directory. On Windows 7 and later, it's located in `c:/Users/<your username>/.diylc/logs`. On Linux and MacOS, it's typically in `/Users/<your username>/.diylc/logs`.
|
||||
* If you are having issues starting the application under MacOS, make sure that 3rd party apps are allowed on your Mac. This document covers how to do it - https://support.apple.com/en-us/HT202491.
|
||||
* Try to look for similar unresolved issues that are already reported to avoid duplicates.
|
||||
* Make sure that you are running the latest version of DIYLC.
|
||||
@@ -12,19 +12,20 @@
|
||||
<ul>
|
||||
<li>platform independence, will run on any machine having Java JRE/JDK 1.6.0_45 or newer </li>
|
||||
<li>easy to use interface, most of the operations can be done using mouse </li>
|
||||
<li>can be used to draw PCB, perfboard, stripboard or point-to-point circuit layouts layouts, schematics and guitar wiring diagrams </li>
|
||||
<li>high flexibility, has the API to allow plug-ins and new components to be added without much trouble </li>
|
||||
<li>draw PCB, perfboard, stripboard or point-to-point circuit layouts layouts, schematics and guitar wiring diagrams </li>
|
||||
<li>high flexibility, has the API to allow plug-ins and new components to be added</li>
|
||||
<li>improved performance and reduced memory consumption compared to the previous versions </li>
|
||||
<li>save default values for each property of a component individually </li>
|
||||
<li>group components together and treat them as one, e.g. move, edit or delete </li>
|
||||
<li>export the output to image, PDF or printer </li>
|
||||
<li>export PCB trace mask suitable for toner transfer </li>
|
||||
<li>export the circuit to a SPICE compatible netlist (beta) </li>
|
||||
<li>create a Bill of Materials as a part of the project or export it to few different file formats </li>
|
||||
<li>analyze guitar wirings and show detailed pickup configuration in each switch configuration</li>
|
||||
<li>zoom in/out feature </li>
|
||||
<li>configurable grid spacing on the project level </li>
|
||||
<li>auto update checks for new versions </li>
|
||||
<li>import files created with older versions of the application </li>
|
||||
<li>create and load project templates </li>
|
||||
<li>cloud feature - share your projects, search through the cloud and download other users' projects </li>
|
||||
<li>highlight connected areas to simplify validation and circuit debugging</li>
|
||||
</ul>
|
||||
@@ -44,6 +45,6 @@
|
||||
<p></p>
|
||||
<h3><a name="Credits"></a>Credits<a href="#Credits" class="section_anchor"></a></h3>
|
||||
<ul>
|
||||
<li>Big thanks goes to folks from the following sites that helped with testing and ideas: <a href="http://www.diystompboxes.com/smfforum/" rel="nofollow">DIY Stompboxes</a>, <a href="http://ax84.com/bbs" rel="nofollow">AX84</a> and <a href="http://freestompboxes.org" rel="nofollow">Free Stompboxes</a>. </li>
|
||||
<li>Big thanks goes to folks from the following online communities for contributing ideas and helped test the app: <a href="http://www.diystompboxes.com/smfforum/" rel="nofollow">DIY Stompboxes</a>, <a href="http://ax84.com/bbs" rel="nofollow">AX84</a> and <a href="http://freestompboxes.org" rel="nofollow">Free Stompboxes</a>. </li>
|
||||
<li>I'm happy to report that DIYLC 3 is the fastest version ever. <a href="http://www.yourkit.com/java/profiler/index.jsp" rel="nofollow">YourKit Java Profiler</a> helped tremendously with memory and performance profiling and pointed me to places in the code that took longer to run or consumed more memory than I'd like them to. I strongly recommend this tool to anyone developing Java or .NET applications because it helps finding bottlenecks and allocation hot-spots very fast.<br><br>YourKit is kindly supporting open source projects with its full-featured Java Profiler.<br>YourKit, LLC is the creator of innovative and intelligent tools for profiling Java and .NET applications.<br>Take a look at YourKit's leading software products: <a href="http://www.yourkit.com/java/profiler/index.jsp" rel="nofollow">YourKit Java Profiler</a> and <a href="http://www.yourkit.com/.net/profiler/index.jsp" rel="nofollow">YourKit .NET Profiler</a> </li>
|
||||
</ul>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
eclipse.preferences.version=1
|
||||
encoding//src/org/diylc/core/measures/Resistance.java=UTF-8
|
||||
encoding//src/org/diylc/core/measures/ResistanceUnit.java=UTF-8
|
||||
Binary file not shown.
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2018 held jointly by the individual authors.
|
||||
|
||||
This file is part of DIYLC.
|
||||
|
||||
DIYLC is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DIYLC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package org.diylc.common;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.diylc.core.IDIYComponent;
|
||||
|
||||
public class BuildingBlockPackage {
|
||||
|
||||
private Map<String, List<IDIYComponent<?>>> block;
|
||||
private String owner;
|
||||
|
||||
public BuildingBlockPackage(Map<String, List<IDIYComponent<?>>> blocks, String owner) {
|
||||
super();
|
||||
this.block = blocks;
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
public Map<String, List<IDIYComponent<?>>> getBlocks() {
|
||||
return block;
|
||||
}
|
||||
|
||||
public String getOwner() {
|
||||
return owner;
|
||||
}
|
||||
}
|
||||
@@ -43,18 +43,16 @@ public class ComponentType {
|
||||
private Class<? extends IDIYComponent<?>> instanceClass;
|
||||
private double zOrder;
|
||||
private boolean flexibleZOrder;
|
||||
private boolean stretchable;
|
||||
private BomPolicy bomPolicy;
|
||||
private boolean autoEdit;
|
||||
private IComponentTransformer transformer;
|
||||
private KeywordPolicy keywordPolicy;
|
||||
private String keywordTag;
|
||||
private boolean continuity;
|
||||
|
||||
public ComponentType(String name, String description, CreationMethod creationMethod, String category,
|
||||
String namePrefix, String author, Icon icon, Class<? extends IDIYComponent<?>> instanceClass, double zOrder,
|
||||
boolean flexibleZOrder, boolean stretchable, BomPolicy bomPolicy, boolean autoEdit,
|
||||
IComponentTransformer transformer, KeywordPolicy keywordPolicy, String keywordTag, boolean continuity) {
|
||||
boolean flexibleZOrder, BomPolicy bomPolicy, boolean autoEdit, IComponentTransformer transformer,
|
||||
KeywordPolicy keywordPolicy, String keywordTag) {
|
||||
super();
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
@@ -66,13 +64,11 @@ public class ComponentType {
|
||||
this.instanceClass = instanceClass;
|
||||
this.zOrder = zOrder;
|
||||
this.flexibleZOrder = flexibleZOrder;
|
||||
this.stretchable = stretchable;
|
||||
this.bomPolicy = bomPolicy;
|
||||
this.autoEdit = autoEdit;
|
||||
this.transformer = transformer;
|
||||
this.keywordPolicy = keywordPolicy;
|
||||
this.keywordTag = keywordTag;
|
||||
this.continuity = continuity;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
@@ -115,10 +111,6 @@ public class ComponentType {
|
||||
return flexibleZOrder;
|
||||
}
|
||||
|
||||
public boolean isStretchable() {
|
||||
return stretchable;
|
||||
}
|
||||
|
||||
public BomPolicy getBomPolicy() {
|
||||
return bomPolicy;
|
||||
}
|
||||
@@ -139,10 +131,6 @@ public class ComponentType {
|
||||
return keywordTag;
|
||||
}
|
||||
|
||||
public boolean isContinuity() {
|
||||
return continuity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
|
||||
@@ -56,5 +56,9 @@ public enum DrawOption {
|
||||
/**
|
||||
* Draw components in outline mode.
|
||||
*/
|
||||
OUTLINE_MODE;
|
||||
OUTLINE_MODE,
|
||||
/**
|
||||
* Include extra space around the layout.
|
||||
*/
|
||||
EXTRA_SPACE;
|
||||
}
|
||||
|
||||
@@ -85,7 +85,8 @@ public enum EventType {
|
||||
AVAILABLE_CTRL_POINTS_CHANGED,
|
||||
/**
|
||||
* Called when mouse cursor is moved. Point object is passed, containing the current cursor
|
||||
* location (not taking zoom into account).
|
||||
* location (not taking zoom into account) in pixels and two {@link Point2D} objects with coordinates in
|
||||
* inches and mm
|
||||
*/
|
||||
MOUSE_MOVED,
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2018 held jointly by the individual authors.
|
||||
|
||||
This file is part of DIYLC.
|
||||
|
||||
DIYLC is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DIYLC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package org.diylc.common;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class Favorite implements Serializable, Comparable<Favorite> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private FavoriteType type;
|
||||
private String name;
|
||||
|
||||
public Favorite(FavoriteType type, String name) {
|
||||
super();
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public FavoriteType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||
result = prime * result + ((type == null) ? 0 : type.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
Favorite other = (Favorite) obj;
|
||||
if (name == null) {
|
||||
if (other.name != null)
|
||||
return false;
|
||||
} else if (!name.equals(other.name))
|
||||
return false;
|
||||
if (type != other.type)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return type + ":" + name;
|
||||
}
|
||||
|
||||
public enum FavoriteType {
|
||||
Component, Block
|
||||
}
|
||||
|
||||
public String toDisplay() {
|
||||
String[] parts = name.split("\\.");
|
||||
return parts[parts.length - 1];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Favorite o) {
|
||||
return toDisplay().compareToIgnoreCase(o.toDisplay());
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,8 @@
|
||||
*/
|
||||
package org.diylc.common;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface IBlockProcessor {
|
||||
|
||||
public static final String BLOCKS_KEY = "buildingBlocks";
|
||||
@@ -31,6 +33,8 @@ public interface IBlockProcessor {
|
||||
|
||||
void deleteBlock(String blockName);
|
||||
|
||||
int importBlocks(String fileName) throws IOException;
|
||||
|
||||
public class BlockAlreadyExistsException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2018 held jointly by the individual authors.
|
||||
|
||||
This file is part of DIYLC.
|
||||
|
||||
DIYLC is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DIYLC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package org.diylc.common;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.diylc.netlist.Netlist;
|
||||
import org.diylc.netlist.Node;
|
||||
import org.diylc.netlist.Summary;
|
||||
import org.diylc.netlist.TreeException;
|
||||
|
||||
public interface INetlistAnalyzer {
|
||||
|
||||
/**
|
||||
* @return summarizer name
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* @return name of the icon to use
|
||||
*/
|
||||
String getIconName();
|
||||
|
||||
/**
|
||||
* Summarizes all {@link Netlist}s provided.
|
||||
*
|
||||
* @param netlists
|
||||
* @param preferredOutput optional, needed only where there's more than one possible output node.
|
||||
* @return
|
||||
* @throws TreeException
|
||||
*/
|
||||
List<Summary> summarize(List<Netlist> netlists, Node preferredOutput) throws TreeException;
|
||||
|
||||
/**
|
||||
* @return name of the font to be used for display.
|
||||
*/
|
||||
String getFontName();
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2018 held jointly by the individual authors.
|
||||
|
||||
This file is part of DIYLC.
|
||||
|
||||
DIYLC is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DIYLC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package org.diylc.common;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.diylc.netlist.Netlist;
|
||||
|
||||
/**
|
||||
* Interface for {@link Netlist} related operations.
|
||||
*
|
||||
* @author Branislav Stojkovic
|
||||
*/
|
||||
public interface INetlistProcessor {
|
||||
|
||||
/**
|
||||
* Finds all {@link Netlist}s for each switch position combination.
|
||||
*
|
||||
* @param includeSwitches
|
||||
* @return
|
||||
*/
|
||||
List<Netlist> extractNetlists(boolean includeSwitches);
|
||||
|
||||
/**
|
||||
* Finds all available {@link INetlistAnalyzer} implementations.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
List<INetlistAnalyzer> getNetlistAnalyzers();
|
||||
|
||||
|
||||
}
|
||||
@@ -33,6 +33,7 @@ import java.util.Set;
|
||||
|
||||
import org.diylc.appframework.simplemq.IMessageListener;
|
||||
import org.diylc.appframework.simplemq.MessageDispatcher;
|
||||
import org.diylc.appframework.update.Version;
|
||||
import org.diylc.appframework.update.VersionNumber;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.Project;
|
||||
@@ -51,8 +52,8 @@ import org.diylc.core.Theme;
|
||||
* @see IMessageListener
|
||||
* @see EventType
|
||||
*/
|
||||
public interface IPlugInPort extends ISelectionProcessor, IMouseProcessor, IKeyProcessor, ITemplateProcessor,
|
||||
IBlockProcessor {
|
||||
public interface IPlugInPort extends ISelectionProcessor, IMouseProcessor, IKeyProcessor, IVariantProcessor,
|
||||
IBlockProcessor, INetlistProcessor {
|
||||
|
||||
public static final String ANTI_ALIASING_KEY = "antiAliasing";
|
||||
public static final String HI_QUALITY_RENDER_KEY = "hiQualityRender";
|
||||
@@ -72,6 +73,9 @@ public interface IPlugInPort extends ISelectionProcessor, IMouseProcessor, IKeyP
|
||||
public static final String SHOW_RULERS_KEY = "showRulers";
|
||||
public static final String SHOW_GRID_KEY = "showGrid";
|
||||
public static final String HIGHLIGHT_CONTINUITY_AREA = "highlightContinuityArea";
|
||||
public static final String HARDWARE_ACCELERATION = "hardwareAcceleration";
|
||||
public static final String EXTRA_SPACE_KEY = "extraSpace";
|
||||
public static final String FAVORITES_KEY = "favorites";
|
||||
|
||||
public static final int DND_TOGGLE_STICKY = 0x1;
|
||||
public static final int DND_TOGGLE_SNAP = 0x40000000;
|
||||
@@ -90,10 +94,11 @@ public interface IPlugInPort extends ISelectionProcessor, IMouseProcessor, IKeyP
|
||||
* unit. If <code>useZoom</code> is set to true, the result is scaled by zoom factor.
|
||||
*
|
||||
* @param useZoom
|
||||
* @param includeExtraSpace
|
||||
*
|
||||
* @return canvas dimensions
|
||||
*/
|
||||
Dimension getCanvasDimensions(boolean useZoom);
|
||||
Dimension getCanvasDimensions(boolean useZoom, boolean includeExtraSpace);
|
||||
|
||||
/**
|
||||
* Returns an instance of {@link Cursor} that should be used at the specified location.
|
||||
@@ -117,8 +122,9 @@ public interface IPlugInPort extends ISelectionProcessor, IMouseProcessor, IKeyP
|
||||
*
|
||||
* @param project
|
||||
* @param freshStart
|
||||
* @param optional file name when loading from a file
|
||||
*/
|
||||
void loadProject(Project project, boolean freshStart);
|
||||
void loadProject(Project project, boolean freshStart, String filename);
|
||||
|
||||
/**
|
||||
* Creates a new project.
|
||||
@@ -173,8 +179,9 @@ public interface IPlugInPort extends ISelectionProcessor, IMouseProcessor, IKeyP
|
||||
* @param g2d
|
||||
* @param drawOptions specific drawing options
|
||||
* @param filter
|
||||
* @param externalZoom
|
||||
*/
|
||||
void draw(Graphics2D g2d, Set<DrawOption> drawOptions, IComponentFiler filter);
|
||||
void draw(Graphics2D g2d, Set<DrawOption> drawOptions, IComponentFiler filter, Double externalZoom);
|
||||
|
||||
Double[] getAvailableZoomLevels();
|
||||
|
||||
@@ -199,12 +206,20 @@ public interface IPlugInPort extends ISelectionProcessor, IMouseProcessor, IKeyP
|
||||
*/
|
||||
VersionNumber getCurrentVersionNumber();
|
||||
|
||||
/**
|
||||
* Returns few most recent versions.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
List<Version> getRecentUpdates();
|
||||
|
||||
/**
|
||||
* Adds a list of components to the project.
|
||||
*
|
||||
* @param components
|
||||
* @param autoGroup
|
||||
*/
|
||||
void pasteComponents(Collection<IDIYComponent<?>> components);
|
||||
void pasteComponents(Collection<IDIYComponent<?>> components, boolean autoGroup);
|
||||
|
||||
/**
|
||||
* Duplicates selected components and places them nearby.
|
||||
@@ -268,8 +283,9 @@ public interface IPlugInPort extends ISelectionProcessor, IMouseProcessor, IKeyP
|
||||
*
|
||||
* @param componentType
|
||||
* @param template
|
||||
* @param forceInstatiate
|
||||
*/
|
||||
void setNewComponentTypeSlot(ComponentType componentType, Template template);
|
||||
void setNewComponentTypeSlot(ComponentType componentType, Template template, boolean forceInstatiate);
|
||||
|
||||
/**
|
||||
* Changes default size notation, true for metric, false for imperial.
|
||||
@@ -339,4 +355,9 @@ public interface IPlugInPort extends ISelectionProcessor, IMouseProcessor, IKeyP
|
||||
* @param xAxisFirst
|
||||
*/
|
||||
void renumberSelectedComponents(boolean xAxisFirst);
|
||||
|
||||
/**
|
||||
* @return size of extra space around the canvas
|
||||
*/
|
||||
double getExtraSpace();
|
||||
}
|
||||
|
||||
+14
-8
@@ -21,27 +21,33 @@
|
||||
*/
|
||||
package org.diylc.common;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import org.diylc.core.Template;
|
||||
|
||||
public interface ITemplateProcessor {
|
||||
public interface IVariantProcessor {
|
||||
|
||||
public static final String TEMPLATES_KEY = "templates";
|
||||
public static final String DEFAULT_TEMPLATES_KEY = "defaultTemplates";
|
||||
|
||||
void saveSelectedComponentAsTemplate(String templateName);
|
||||
void saveSelectedComponentAsVariant(String variantName);
|
||||
|
||||
List<Template> getTemplatesFor(String categoryName, String componentTypeName);
|
||||
List<Template> getVariantsFor(ComponentType type);
|
||||
|
||||
List<Template> getTemplatesForSelection();
|
||||
List<Template> getVariantsForSelection();
|
||||
|
||||
void applyTemplateToSelection(Template template);
|
||||
void applyVariantToSelection(Template variant);
|
||||
|
||||
void deleteTemplate(String categoryName, String componentTypeName, String templateName);
|
||||
void deleteVariant(ComponentType type, String variantName);
|
||||
|
||||
void setTemplateDefault(String categoryName, String componentTypeName, String templateName, boolean defaultFlag);
|
||||
void setDefaultVariant(ComponentType type, String variantName);
|
||||
|
||||
public class TemplateAlreadyExistsException extends Exception {
|
||||
int importVariants(String fileName) throws IOException;
|
||||
|
||||
String getDefaultVariant(ComponentType type);
|
||||
|
||||
public class VariantAlreadyExistsException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@@ -43,6 +43,7 @@ public class ObjectCache {
|
||||
private ObjectCache() {}
|
||||
|
||||
private Map<Float, Stroke> basicStrokeMap = new HashMap<Float, Stroke>();
|
||||
private Map<Float, Stroke> zoomableStrokeMap = new HashMap<Float, Stroke>();
|
||||
private Map<String, Stroke> dashStrokeMap = new HashMap<String, Stroke>();
|
||||
|
||||
public Stroke fetchBasicStroke(float width) {
|
||||
@@ -54,12 +55,21 @@ public class ObjectCache {
|
||||
return stroke;
|
||||
}
|
||||
|
||||
public Stroke fetchStroke(float width, float[] dash, float phase) {
|
||||
String key = width + "|" + Arrays.toString(dash) + "|" + phase;
|
||||
public Stroke fetchZoomableStroke(float width) {
|
||||
if (zoomableStrokeMap.containsKey(width)) {
|
||||
return zoomableStrokeMap.get(width);
|
||||
}
|
||||
Stroke stroke = new ZoomableStroke(width, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
|
||||
zoomableStrokeMap.put(width, stroke);
|
||||
return stroke;
|
||||
}
|
||||
|
||||
public Stroke fetchStroke(float width, float[] dash, float phase, int cap) {
|
||||
String key = width + "|" + Arrays.toString(dash) + "|" + phase + "|" + phase;
|
||||
if (dashStrokeMap.containsKey(key)) {
|
||||
return dashStrokeMap.get(key);
|
||||
}
|
||||
Stroke stroke = new BasicStroke(width, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 0, dash, phase);
|
||||
Stroke stroke = new BasicStroke(width, cap, BasicStroke.JOIN_ROUND, 0, dash, phase);
|
||||
dashStrokeMap.put(key, stroke);
|
||||
return stroke;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2018 held jointly by the individual authors.
|
||||
|
||||
This file is part of DIYLC.
|
||||
|
||||
DIYLC is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DIYLC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package org.diylc.common;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.diylc.core.Template;
|
||||
|
||||
public class VariantPackage {
|
||||
|
||||
private Map<String, List<Template>> variants;
|
||||
private String owner;
|
||||
|
||||
public VariantPackage(Map<String, List<Template>> variants, String owner) {
|
||||
super();
|
||||
this.variants = variants;
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
public Map<String, List<Template>> getVariants() {
|
||||
return variants;
|
||||
}
|
||||
|
||||
public String getOwner() {
|
||||
return owner;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2018 held jointly by the individual authors.
|
||||
|
||||
This file is part of DIYLC.
|
||||
|
||||
DIYLC is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DIYLC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package org.diylc.common;
|
||||
|
||||
import java.awt.BasicStroke;
|
||||
|
||||
/***
|
||||
* {@link BasicStroke} that will always be zoomed in when rendered.
|
||||
*
|
||||
* @author Branislav Stojkovic
|
||||
*/
|
||||
public class ZoomableStroke extends BasicStroke {
|
||||
|
||||
public ZoomableStroke() {
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public ZoomableStroke(float width) {
|
||||
super(width);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public ZoomableStroke(float width, int cap, int join) {
|
||||
super(width, cap, join);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public ZoomableStroke(float width, int cap, int join, float miterlimit) {
|
||||
super(width, cap, join, miterlimit);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public ZoomableStroke(float width, int cap, int join, float miterlimit, float[] dash, float dash_phase) {
|
||||
super(width, cap, join, miterlimit, dash, dash_phase);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
}
|
||||
@@ -23,21 +23,14 @@ package org.diylc.components;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Shape;
|
||||
import java.awt.font.FontRenderContext;
|
||||
import java.awt.font.GlyphVector;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.diylc.common.HorizontalAlignment;
|
||||
import org.diylc.common.VerticalAlignment;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.annotations.EditableProperty;
|
||||
|
||||
@@ -61,8 +54,9 @@ public abstract class AbstractComponent<T> implements IDIYComponent<T> {
|
||||
public static Color SELECTION_COLOR = Color.red;
|
||||
public static Color LABEL_COLOR = Color.black;
|
||||
public static Color LABEL_COLOR_SELECTED = Color.red;
|
||||
public static Font LABEL_FONT = new Font("Tahoma", Font.PLAIN, 14);
|
||||
public static Font LABEL_FONT = new Font("Square721 BT", Font.PLAIN, 14);
|
||||
public static Color METAL_COLOR = Color.decode("#759DAF");
|
||||
public static Color LIGHT_METAL_COLOR = Color.decode("#EEEEEE");
|
||||
public static Color COPPER_COLOR = Color.decode("#DA8A67");
|
||||
|
||||
@EditableProperty(defaultable = false)
|
||||
@@ -146,45 +140,6 @@ public abstract class AbstractComponent<T> implements IDIYComponent<T> {
|
||||
return !clip.intersects(rect);
|
||||
}
|
||||
|
||||
protected void drawCenteredText(Graphics2D g2d, String text, int x, int y, HorizontalAlignment horizontalAlignment,
|
||||
VerticalAlignment verticalAlignment) {
|
||||
FontMetrics fontMetrics = g2d.getFontMetrics();
|
||||
Rectangle stringBounds = fontMetrics.getStringBounds(text, g2d).getBounds();
|
||||
|
||||
Font font = g2d.getFont();
|
||||
FontRenderContext renderContext = g2d.getFontRenderContext();
|
||||
GlyphVector glyphVector = font.createGlyphVector(renderContext, text);
|
||||
Rectangle visualBounds = glyphVector.getVisualBounds().getBounds();
|
||||
|
||||
int textX = 0;
|
||||
switch (horizontalAlignment) {
|
||||
case CENTER:
|
||||
textX = x - stringBounds.width / 2;
|
||||
break;
|
||||
case LEFT:
|
||||
textX = x;
|
||||
break;
|
||||
case RIGHT:
|
||||
textX = x - stringBounds.width;
|
||||
break;
|
||||
}
|
||||
|
||||
int textY = 0;
|
||||
switch (verticalAlignment) {
|
||||
case TOP:
|
||||
textY = y + stringBounds.height;
|
||||
break;
|
||||
case CENTER:
|
||||
textY = y - visualBounds.height / 2 - visualBounds.y;
|
||||
break;
|
||||
case BOTTOM:
|
||||
textY = y - visualBounds.y;
|
||||
break;
|
||||
}
|
||||
|
||||
g2d.drawString(text, textX, textY);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public IDIYComponent<T> clone() throws CloneNotSupportedException {
|
||||
try {
|
||||
@@ -266,8 +221,35 @@ public abstract class AbstractComponent<T> implements IDIYComponent<T> {
|
||||
if (o1 == null || o2 == null)
|
||||
return false;
|
||||
if (o1.getClass().isArray()) {
|
||||
if (o1.getClass().getComponentType() == byte.class)
|
||||
return Arrays.equals((byte[]) o1, (byte[]) o2);
|
||||
return Arrays.equals((Object[]) o1, (Object[]) o2);
|
||||
}
|
||||
return o1.equals(o2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getControlPointNodeName(int index) {
|
||||
return Integer.toString(index + 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInternalLinkName(int index1, int index2) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getSectionNames(int pointIndex) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommonPointName(int pointIndex) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPointMoveFreely(int pointIndex) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ public abstract class AbstractCurvedComponent<T> extends AbstractTransparentComp
|
||||
if (getPointCount() == PointCount.TWO) {
|
||||
path.lineTo(p[1].x, p[1].y);
|
||||
} else if (getPointCount() == PointCount.THREE) {
|
||||
path.quadTo(p[1].x, p[1].y, p[2].x, p[2].y);
|
||||
path.curveTo(p[1].x, p[1].y, p[1].x, p[1].y, p[2].x, p[2].y);
|
||||
} else if (getPointCount() == PointCount.FOUR) {
|
||||
path.curveTo(p[1].x, p[1].y, p[2].x, p[2].y, p[3].x, p[3].y);
|
||||
} else if (getPointCount() == PointCount.FIVE) {
|
||||
@@ -322,7 +322,7 @@ public abstract class AbstractCurvedComponent<T> extends AbstractTransparentComp
|
||||
// }
|
||||
}
|
||||
|
||||
enum PointCount {
|
||||
public enum PointCount {
|
||||
TWO(2), THREE(3), FOUR(4), FIVE(5), SEVEN(7);
|
||||
|
||||
private int count;
|
||||
|
||||
@@ -1,482 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* DIY Layout Creator (DIYLC). Copyright (c) 2009-2018 held jointly by the individual authors.
|
||||
*
|
||||
* This file is part of DIYLC.
|
||||
*
|
||||
* DIYLC is free software: you can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* DIYLC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with DIYLC. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.diylc.components;
|
||||
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.Color;
|
||||
import java.awt.Composite;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Shape;
|
||||
import java.awt.Stroke;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
import org.diylc.appframework.miscutils.ConfigurationManager;
|
||||
import org.diylc.common.Display;
|
||||
import org.diylc.common.IPlugInPort;
|
||||
import org.diylc.common.LineStyle;
|
||||
import org.diylc.common.ObjectCache;
|
||||
import org.diylc.core.ComponentState;
|
||||
import org.diylc.core.IDrawingObserver;
|
||||
import org.diylc.core.Project;
|
||||
import org.diylc.core.Theme;
|
||||
import org.diylc.core.VisibilityPolicy;
|
||||
import org.diylc.core.annotations.EditableProperty;
|
||||
import org.diylc.core.measures.Size;
|
||||
import org.diylc.core.measures.SizeUnit;
|
||||
import org.diylc.utils.Constants;
|
||||
|
||||
/**
|
||||
* Base class for all leaded components such as resistors or capacitors. Has two control points and
|
||||
* draws leads between them. Also, it positions and draws the shape of the component as specified by
|
||||
* a child class.
|
||||
*
|
||||
* @author Branislav Stojkovic
|
||||
*/
|
||||
public abstract class AbstractLeadedComponent<T> extends AbstractTransparentComponent<T> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static Color LEAD_COLOR = Color.decode("#CCCCCC");
|
||||
public static Color LEAD_COLOR_ICON = LEAD_COLOR.darker().darker();
|
||||
public static Size LEAD_THICKNESS = new Size(0.6d, SizeUnit.mm);
|
||||
public static Size DEFAULT_SIZE = new Size(1d, SizeUnit.in);
|
||||
|
||||
protected Size length;
|
||||
protected Size width;
|
||||
protected Point[] points = new Point[] {new Point((int) (-DEFAULT_SIZE.convertToPixels() / 2), 0),
|
||||
new Point((int) (DEFAULT_SIZE.convertToPixels() / 2), 0)};
|
||||
protected Color bodyColor = Color.white;
|
||||
protected Color borderColor = Color.black;
|
||||
protected Color labelColor = LABEL_COLOR;
|
||||
protected Color leadColor = LEAD_COLOR;
|
||||
protected Display display = Display.NAME;
|
||||
private boolean flipStanding = false;
|
||||
|
||||
protected AbstractLeadedComponent() {
|
||||
super();
|
||||
try {
|
||||
this.length = getDefaultLength().clone();
|
||||
this.width = getDefaultWidth().clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
// This should never happen because Size supports cloning.
|
||||
} catch (NullPointerException e) {
|
||||
// This will happen if components do not have any shape.
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean IsCopperArea() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project,
|
||||
IDrawingObserver drawingObserver) {
|
||||
double distance = points[0].distance(points[1]);
|
||||
Shape shape = getBodyShape();
|
||||
// If there's no body, just draw the line connecting the ending points.
|
||||
if (shape == null) {
|
||||
drawLead(g2d, componentState, drawingObserver, IsCopperArea());
|
||||
} else if (supportsStandingMode() && length.convertToPixels() > points[0].distance(points[1])) {
|
||||
// When ending points are too close draw the component in standing
|
||||
// mode.
|
||||
int width = getClosestOdd(this.width.convertToPixels());
|
||||
Shape body =
|
||||
new Ellipse2D.Double((getFlipStanding() ? points[1] : points[0]).x - width / 2,
|
||||
(getFlipStanding() ? points[1] : points[0]).y - width / 2, width, width);
|
||||
Composite oldComposite = g2d.getComposite();
|
||||
if (alpha < MAX_ALPHA) {
|
||||
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA));
|
||||
}
|
||||
g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getStandingBodyColor());
|
||||
g2d.fill(body);
|
||||
g2d.setComposite(oldComposite);
|
||||
Color finalBorderColor;
|
||||
if (outlineMode) {
|
||||
Theme theme =
|
||||
(Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME);
|
||||
finalBorderColor =
|
||||
componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR
|
||||
: theme.getOutlineColor();
|
||||
} else {
|
||||
finalBorderColor =
|
||||
componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR
|
||||
: borderColor;
|
||||
}
|
||||
|
||||
g2d.setColor(finalBorderColor);
|
||||
g2d.draw(body);
|
||||
if (!outlineMode) {
|
||||
drawLead(g2d, componentState, drawingObserver, false);
|
||||
}
|
||||
} else {
|
||||
// Normal mode with component body in the center and two lead parts.
|
||||
Rectangle shapeRect = shape.getBounds();
|
||||
double theta = Math.atan2(points[1].y - points[0].y, points[1].x - points[0].x);
|
||||
// Go back to the original transformation to draw leads.
|
||||
if (!outlineMode) {
|
||||
AffineTransform textTransform = g2d.getTransform();
|
||||
// if (length.convertToPixels() > points[0].distance(points[1]))
|
||||
// {
|
||||
// g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
|
||||
// 0.5f));
|
||||
// }
|
||||
float leadThickness = getLeadThickness();
|
||||
double leadLength = (distance - calculatePinSpacing(shapeRect)) / 2;
|
||||
|
||||
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness));
|
||||
Color leadColor =
|
||||
shouldShadeLeads() ? getLeadColorForPainting(componentState).darker()
|
||||
: getLeadColorForPainting(componentState);
|
||||
g2d.setColor(leadColor);
|
||||
drawLeads(g2d, theta, leadLength);
|
||||
|
||||
if (shouldShadeLeads()) {
|
||||
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness - 2));
|
||||
leadColor = getLeadColorForPainting(componentState);
|
||||
g2d.setColor(leadColor);
|
||||
drawLeads(g2d, theta, leadLength);
|
||||
}
|
||||
g2d.setTransform(textTransform);
|
||||
}
|
||||
// Transform graphics to draw the body in the right place and at the
|
||||
// right angle.
|
||||
AffineTransform oldTransform = null;
|
||||
double width;
|
||||
double length;
|
||||
if (useShapeRectAsPosition()) {
|
||||
width = shapeRect.getHeight();
|
||||
length = shapeRect.getWidth();
|
||||
} else {
|
||||
width = getWidth().convertToPixels();
|
||||
length = getLength().convertToPixels();
|
||||
}
|
||||
oldTransform = g2d.getTransform();
|
||||
g2d.translate((points[0].x + points[1].x - length) / 2, (points[0].y + points[1].y - width) / 2);
|
||||
g2d.rotate(theta, length / 2, width / 2);
|
||||
// Draw body.
|
||||
Composite oldComposite = g2d.getComposite();
|
||||
if (alpha < MAX_ALPHA) {
|
||||
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA));
|
||||
}
|
||||
if (bodyColor != null) {
|
||||
g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : bodyColor);
|
||||
g2d.fill(shape);
|
||||
}
|
||||
decorateComponentBody(g2d, outlineMode);
|
||||
g2d.setComposite(oldComposite);
|
||||
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1));
|
||||
Color finalBorderColor;
|
||||
if (outlineMode) {
|
||||
Theme theme =
|
||||
(Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME);
|
||||
finalBorderColor =
|
||||
componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR
|
||||
: theme.getOutlineColor();
|
||||
} else {
|
||||
finalBorderColor =
|
||||
componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR
|
||||
: borderColor;
|
||||
}
|
||||
g2d.setColor(finalBorderColor);
|
||||
g2d.draw(shape);
|
||||
|
||||
// Draw label.
|
||||
g2d.setFont(project.getFont());
|
||||
if (useShapeRectAsPosition()) {
|
||||
g2d.translate(shapeRect.x, shapeRect.y);
|
||||
}
|
||||
Color finalLabelColor;
|
||||
if (outlineMode) {
|
||||
Theme theme =
|
||||
(Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME);
|
||||
finalLabelColor =
|
||||
componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED
|
||||
: theme.getOutlineColor();
|
||||
} else {
|
||||
finalLabelColor =
|
||||
componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED
|
||||
: labelColor;
|
||||
}
|
||||
g2d.setColor(finalLabelColor);
|
||||
FontMetrics fontMetrics = g2d.getFontMetrics();
|
||||
String label = "";
|
||||
label = display == Display.NAME ? getName() : (getValue() == null ? "" : getValue().toString());
|
||||
if (display == Display.NONE) {
|
||||
label = "";
|
||||
}
|
||||
if (display == Display.BOTH) {
|
||||
label = getName() + " " + (getValue() == null ? "" : getValue().toString());
|
||||
}
|
||||
Rectangle2D textRect = fontMetrics.getStringBounds(label, g2d);
|
||||
// Don't offset in outline mode.
|
||||
int offset = outlineMode ? 0 : getLabelOffset((int) length, (int) textRect.getWidth());
|
||||
// Adjust label angle if needed to make sure that it's readable.
|
||||
if ((theta >= Math.PI / 2 && theta <= Math.PI) || (theta < -Math.PI / 2 && theta > -Math.PI)) {
|
||||
g2d.rotate(Math.PI, length / 2, width / 2);
|
||||
offset = -offset;
|
||||
}
|
||||
g2d.drawString(label, (int) (length - textRect.getWidth()) / 2 + offset,
|
||||
calculateLabelYCoordinate(shapeRect, textRect, fontMetrics));
|
||||
g2d.setTransform(oldTransform);
|
||||
}
|
||||
}
|
||||
|
||||
private void drawLeads(Graphics2D g2d, double theta, double leadLength) {
|
||||
int endX = (int) (points[0].x + Math.cos(theta) * leadLength);
|
||||
int endY = (int) (points[0].y + Math.sin(theta) * leadLength);
|
||||
g2d.drawLine(points[0].x, points[0].y, endX, endY);
|
||||
|
||||
endX = (int) (points[1].x + Math.cos(theta - Math.PI) * leadLength);
|
||||
endY = (int) (points[1].y + Math.sin(theta - Math.PI) * leadLength);
|
||||
g2d.drawLine(points[1].x, points[1].y, endX, endY);
|
||||
}
|
||||
|
||||
private void drawLead(Graphics2D g2d, ComponentState componentState, IDrawingObserver observer, boolean isCopperArea) {
|
||||
if (isCopperArea)
|
||||
observer.startTrackingContinuityArea(true);
|
||||
|
||||
float thickness = getLeadThickness();
|
||||
Stroke stroke = null;
|
||||
switch (getStyle()) {
|
||||
case SOLID:
|
||||
stroke = ObjectCache.getInstance().fetchBasicStroke(thickness);
|
||||
break;
|
||||
case DASHED:
|
||||
stroke =
|
||||
ObjectCache.getInstance().fetchStroke(thickness, new float[] {thickness * 2, thickness * 4}, thickness * 4);
|
||||
break;
|
||||
case DOTTED:
|
||||
stroke = ObjectCache.getInstance().fetchStroke(thickness, new float[] {thickness / 4, thickness * 4}, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
g2d.setStroke(stroke);
|
||||
Color leadColor =
|
||||
shouldShadeLeads() ? getLeadColorForPainting(componentState).darker() : getLeadColorForPainting(componentState);
|
||||
g2d.setColor(leadColor);
|
||||
g2d.drawLine(points[0].x, points[0].y, points[1].x, points[1].y);
|
||||
|
||||
if (isCopperArea)
|
||||
observer.stopTrackingContinuityArea();
|
||||
|
||||
if (shouldShadeLeads()) {
|
||||
switch (getStyle()) {
|
||||
case SOLID:
|
||||
stroke = ObjectCache.getInstance().fetchBasicStroke(thickness - 2);
|
||||
break;
|
||||
case DASHED:
|
||||
stroke =
|
||||
ObjectCache.getInstance().fetchStroke(thickness - 2, new float[] {thickness * 2, thickness * 4},
|
||||
thickness * 4);
|
||||
break;
|
||||
case DOTTED:
|
||||
stroke = ObjectCache.getInstance().fetchStroke(thickness - 2, new float[] {thickness / 4, thickness * 4}, 0);
|
||||
break;
|
||||
}
|
||||
g2d.setStroke(stroke);
|
||||
leadColor = getLeadColorForPainting(componentState);
|
||||
g2d.setColor(leadColor);
|
||||
g2d.drawLine(points[0].x, points[0].y, points[1].x, points[1].y);
|
||||
}
|
||||
}
|
||||
|
||||
protected LineStyle getStyle() {
|
||||
return LineStyle.SOLID;
|
||||
}
|
||||
|
||||
protected void decorateComponentBody(Graphics2D g2d, boolean outlineMode) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
protected int calculateLabelYCoordinate(Rectangle2D shapeRect, Rectangle2D textRect, FontMetrics fontMetrics) {
|
||||
return (int) (shapeRect.getHeight() - textRect.getHeight()) / 2 + fontMetrics.getAscent();
|
||||
}
|
||||
|
||||
protected boolean shouldShadeLeads() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean supportsStandingMode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected int getLabelOffset(int bodyWidth, int labelWidth) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return default component length.
|
||||
*/
|
||||
protected abstract Size getDefaultLength();
|
||||
|
||||
/**
|
||||
* Returns default component width.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected abstract Size getDefaultWidth();
|
||||
|
||||
/**
|
||||
* @return shape that represents component body. Shape should not be transformed and should be
|
||||
* referenced to (0, 0).
|
||||
*/
|
||||
protected abstract Shape getBodyShape();
|
||||
|
||||
/**
|
||||
* Controls how component shape should be placed relative to start and end point.
|
||||
*
|
||||
* @return <code>true<code> if shape rect should be used to center the component or <code>false</code>
|
||||
* to place the component relative to <code>length</code> and <code>width</code> values.
|
||||
*/
|
||||
protected boolean useShapeRectAsPosition() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return default lead thickness. Override this method to change it.
|
||||
*/
|
||||
protected float getLeadThickness() {
|
||||
return getClosestOdd(LEAD_THICKNESS.convertToPixels());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return default lead color. Override this method to change it.
|
||||
*/
|
||||
protected Color getLeadColorForPainting(ComponentState componentState) {
|
||||
return componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR
|
||||
: getLeadColor();
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Lead color")
|
||||
public Color getLeadColor() {
|
||||
if (leadColor == null) {
|
||||
leadColor = LEAD_COLOR_ICON;
|
||||
}
|
||||
return leadColor;
|
||||
}
|
||||
|
||||
public void setLeadColor(Color leadColor) {
|
||||
this.leadColor = leadColor;
|
||||
}
|
||||
|
||||
protected int calculatePinSpacing(Rectangle shapeRect) {
|
||||
return shapeRect.width;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getControlPointCount() {
|
||||
return points.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Point getControlPoint(int index) {
|
||||
return (Point) points[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isControlPointSticky(int index) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VisibilityPolicy getControlPointVisibilityPolicy(int index) {
|
||||
return VisibilityPolicy.ALWAYS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setControlPoint(Point point, int index) {
|
||||
points[index].setLocation(point);
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Color")
|
||||
public Color getBodyColor() {
|
||||
return bodyColor;
|
||||
}
|
||||
|
||||
public void setBodyColor(Color bodyColor) {
|
||||
this.bodyColor = bodyColor;
|
||||
}
|
||||
|
||||
public Color getStandingBodyColor() {
|
||||
return bodyColor;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Border")
|
||||
public Color getBorderColor() {
|
||||
return borderColor;
|
||||
}
|
||||
|
||||
public void setBorderColor(Color borderColor) {
|
||||
this.borderColor = borderColor;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Length", defaultable = true)
|
||||
public Size getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
public void setLength(Size length) {
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Width", defaultable = true)
|
||||
public Size getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public void setWidth(Size width) {
|
||||
this.width = width;
|
||||
}
|
||||
|
||||
@EditableProperty
|
||||
public Display getDisplay() {
|
||||
return display;
|
||||
}
|
||||
|
||||
public void setDisplay(Display display) {
|
||||
this.display = display;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Label color")
|
||||
public Color getLabelColor() {
|
||||
return labelColor;
|
||||
}
|
||||
|
||||
public void setLabelColor(Color labelColor) {
|
||||
this.labelColor = labelColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this method with @EditableProperty annotation in child classes where standing mode is
|
||||
* supported
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean getFlipStanding() {
|
||||
return flipStanding;
|
||||
}
|
||||
|
||||
public void setFlipStanding(boolean flipStanding) {
|
||||
this.flipStanding = flipStanding;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2018 held jointly by the individual authors.
|
||||
|
||||
This file is part of DIYLC.
|
||||
|
||||
DIYLC is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DIYLC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package org.diylc.core;
|
||||
|
||||
public interface IContinuity {
|
||||
|
||||
/**
|
||||
* Tests control point connectivity.
|
||||
*
|
||||
* @param index1
|
||||
* @param index2
|
||||
* @return true if the two points are connected, false otherwise.
|
||||
*/
|
||||
boolean arePointsConnected(int index1, int index2);
|
||||
}
|
||||
@@ -111,8 +111,44 @@ public interface IDIYComponent<T> extends Serializable {
|
||||
*/
|
||||
boolean canControlPointOverlap(int index);
|
||||
|
||||
/**
|
||||
* @param index
|
||||
* @return {@link VisibilityPolicy} of the control point.
|
||||
*/
|
||||
VisibilityPolicy getControlPointVisibilityPolicy(int index);
|
||||
|
||||
/**
|
||||
* @param index
|
||||
* @return name of the control point node, if the control point represents a graph node, null otherwise.
|
||||
*/
|
||||
String getControlPointNodeName(int index);
|
||||
|
||||
/**
|
||||
* @param index1
|
||||
* @param index2
|
||||
* @return name of the internal linked formed by the two control points, null if they do not form an internal link
|
||||
*/
|
||||
String getInternalLinkName(int index1, int index2);
|
||||
|
||||
/**
|
||||
* @param pointIndex
|
||||
* @return name of the internal section containing the specified point, or null if the component does not have internal sections.
|
||||
* One point can be shared between multiple sections, in which case, the result may contain more than one element.
|
||||
*/
|
||||
String[] getSectionNames(int pointIndex);
|
||||
|
||||
/**
|
||||
* @param pointIndex
|
||||
* @return name of the common point that joins all the other points with the same name together, e.g. GND
|
||||
*/
|
||||
String getCommonPointName(int pointIndex);
|
||||
|
||||
/**
|
||||
* @param pointIndex
|
||||
* @return true if the control point can move without affecting other points' position, false otherwise
|
||||
*/
|
||||
boolean canPointMoveFreely(int pointIndex);
|
||||
|
||||
/**
|
||||
* Draws the component onto the {@link Graphics2D}.
|
||||
*
|
||||
|
||||
@@ -36,4 +36,6 @@ public interface IDrawingObserver {
|
||||
void stopTrackingContinuityArea();
|
||||
|
||||
void startTrackingContinuityArea(boolean positive);
|
||||
|
||||
boolean isTrackingContinuityArea();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2018 held jointly by the individual authors.
|
||||
|
||||
This file is part of DIYLC.
|
||||
|
||||
DIYLC is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DIYLC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package org.diylc.core;
|
||||
|
||||
/**
|
||||
* Interface for all component that can act as switches. They must have at least one position.
|
||||
*
|
||||
* @author Branislav Stojkovic
|
||||
*/
|
||||
public interface ISwitch {
|
||||
|
||||
/**
|
||||
* @return a positive number of positions.
|
||||
*/
|
||||
int getPositionCount();
|
||||
|
||||
/**
|
||||
* @param position
|
||||
* @return name of switch positions, e.g. "ON", "OFF"...
|
||||
*/
|
||||
String getPositionName(int position);
|
||||
|
||||
/**
|
||||
* Tests control point connectivity.
|
||||
*
|
||||
* @param index1
|
||||
* @param index2
|
||||
* @param position
|
||||
* @return true if the two points are connected in the given switch position, false otherwise.
|
||||
*/
|
||||
boolean arePointsConnected(int index1, int index2, int position);
|
||||
}
|
||||
@@ -53,7 +53,7 @@ public class Project implements Serializable {
|
||||
public static Size DEFAULT_WIDTH = new Size(29d, SizeUnit.cm);
|
||||
public static Size DEFAULT_HEIGHT = new Size(21d, SizeUnit.cm);
|
||||
public static Size DEFAULT_GRID_SPACING = new Size(0.1d, SizeUnit.in);
|
||||
public static Font DEFAULT_FONT = new Font("Tahoma", Font.PLAIN, 14);
|
||||
public static Font DEFAULT_FONT = new Font("Square721 BT", Font.PLAIN, 14);
|
||||
|
||||
private VersionNumber fileVersion;
|
||||
|
||||
@@ -127,7 +127,7 @@ public class Project implements Serializable {
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Grid spacing", validatorClass = SpacingValidator.class, sortOrder = 6)
|
||||
@EditableProperty(name = "Grid Spacing", validatorClass = SpacingValidator.class, sortOrder = 6)
|
||||
public Size getGridSpacing() {
|
||||
return gridSpacing;
|
||||
}
|
||||
@@ -256,6 +256,31 @@ public class Project implements Serializable {
|
||||
return false;
|
||||
} else if (!width.equals(other.width))
|
||||
return false;
|
||||
if (gridSpacing == null) {
|
||||
if (other.gridSpacing != null)
|
||||
return false;
|
||||
} else if (!gridSpacing.equals(other.gridSpacing))
|
||||
return false;
|
||||
if (font == null) {
|
||||
if (other.font != null)
|
||||
return false;
|
||||
} else if (!font.equals(other.font))
|
||||
return false;
|
||||
if (groups == null) {
|
||||
if (other.groups != null)
|
||||
return false;
|
||||
} else if (!groups.equals(other.groups))
|
||||
return false;
|
||||
if (lockedLayers == null) {
|
||||
if (other.lockedLayers != null)
|
||||
return false;
|
||||
} else if (!lockedLayers.equals(other.lockedLayers))
|
||||
return false;
|
||||
if (hiddenLayers == null) {
|
||||
if (other.hiddenLayers != null)
|
||||
return false;
|
||||
} else if (!hiddenLayers.equals(other.hiddenLayers))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -291,6 +316,7 @@ public class Project implements Serializable {
|
||||
project.setWidth(this.getWidth());
|
||||
project.getLockedLayers().addAll(this.getLockedLayers());
|
||||
project.getHiddenLayers().addAll(this.getHiddenLayers());
|
||||
project.setFont(this.getFont());
|
||||
|
||||
Map<IDIYComponent<?>, IDIYComponent<?>> cloneMap = new HashMap<IDIYComponent<?>, IDIYComponent<?>>();
|
||||
|
||||
|
||||
@@ -30,14 +30,17 @@ public class Template {
|
||||
private String name;
|
||||
private Map<String, Object> values;
|
||||
private List<Point> points;
|
||||
@SuppressWarnings("unused")
|
||||
@Deprecated
|
||||
private boolean defaultFlag;
|
||||
|
||||
public Template(String name, Map<String, Object> values, List<Point> points, boolean defaultFlag) {
|
||||
super();
|
||||
public Template() {
|
||||
}
|
||||
|
||||
public Template(String name, Map<String, Object> values, List<Point> points) {
|
||||
this.name = name;
|
||||
this.values = values;
|
||||
this.points = points;
|
||||
this.defaultFlag = defaultFlag;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
@@ -64,19 +67,10 @@ public class Template {
|
||||
this.points = points;
|
||||
}
|
||||
|
||||
public boolean isDefaultFlag() {
|
||||
return defaultFlag;
|
||||
}
|
||||
|
||||
public void setDefaultFlag(boolean defaultFlag) {
|
||||
this.defaultFlag = defaultFlag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + (defaultFlag ? 1231 : 1237);
|
||||
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||
result = prime * result + ((points == null) ? 0 : points.hashCode());
|
||||
result = prime * result + ((values == null) ? 0 : values.hashCode());
|
||||
@@ -92,8 +86,6 @@ public class Template {
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
Template other = (Template) obj;
|
||||
if (defaultFlag != other.defaultFlag)
|
||||
return false;
|
||||
if (name == null) {
|
||||
if (other.name != null)
|
||||
return false;
|
||||
|
||||
@@ -82,12 +82,6 @@ public @interface ComponentDescriptor {
|
||||
*/
|
||||
boolean flexibleZOrder() default false;
|
||||
|
||||
/**
|
||||
* @return when false, moving one control point will cause all the others to move together with
|
||||
* it.
|
||||
*/
|
||||
boolean stretchable() default true;
|
||||
|
||||
/**
|
||||
* @return controls what should be shown the BOM
|
||||
*/
|
||||
@@ -117,12 +111,4 @@ public @interface ComponentDescriptor {
|
||||
* @return
|
||||
*/
|
||||
String keywordTag() default "";
|
||||
|
||||
/**
|
||||
* For components that show continuity between the two ending points, e.d. wires, jumpers, etc.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean continuity() default false;
|
||||
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ public class PositiveMeasureValidator implements IPropertyValidator {
|
||||
if (value instanceof AbstractMeasure) {
|
||||
AbstractMeasure<?> measure = (AbstractMeasure<?>) value;
|
||||
if (measure.getValue() < 0) {
|
||||
throw new ValidationException("must be greater than zero.");
|
||||
throw new ValidationException("must be greater or equal to zero.");
|
||||
}
|
||||
} else {
|
||||
throw new ValidationException("wrong data type, measure expected.");
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2018 held jointly by the individual authors.
|
||||
|
||||
This file is part of DIYLC.
|
||||
|
||||
DIYLC is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DIYLC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package org.diylc.core.annotations;
|
||||
|
||||
import org.diylc.core.IPropertyValidator;
|
||||
import org.diylc.core.ValidationException;
|
||||
import org.diylc.core.measures.AbstractMeasure;
|
||||
|
||||
/**
|
||||
* Validates any generic {@link AbstractMeasure} descendants and makes sure that the value is
|
||||
* positive.
|
||||
*
|
||||
* @author Branislav Stojkovic
|
||||
*/
|
||||
public class PositiveNonZeroMeasureValidator implements IPropertyValidator {
|
||||
|
||||
@Override
|
||||
public void validate(Object value) throws ValidationException {
|
||||
if (value == null)
|
||||
return;
|
||||
if (value instanceof AbstractMeasure) {
|
||||
AbstractMeasure<?> measure = (AbstractMeasure<?>) value;
|
||||
if (measure.getValue() <= 0) {
|
||||
throw new ValidationException("must be greater than zero.");
|
||||
}
|
||||
} else {
|
||||
throw new ValidationException("wrong data type, measure expected.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,7 @@ public enum ResistanceUnit implements Unit {
|
||||
@Override
|
||||
public double getFactor() {
|
||||
return factor;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -21,9 +21,11 @@
|
||||
*/
|
||||
package org.diylc.core.measures;
|
||||
|
||||
import org.diylc.utils.Constants;
|
||||
|
||||
public enum SizeUnit implements Unit {
|
||||
|
||||
mm(1d), cm(10d), m(1e4d), in(25.4d), ft(25.4d * 12), yd(9144d);
|
||||
px(25.4d / Constants.PIXELS_PER_INCH), mm(1d), cm(10d), m(1e4d), in(25.4d), ft(25.4d * 12), yd(9144d);
|
||||
|
||||
double factor;
|
||||
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2018 held jointly by the individual authors.
|
||||
|
||||
This file is part of DIYLC.
|
||||
|
||||
DIYLC is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DIYLC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package org.diylc.netlist;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.diylc.core.IDIYComponent;
|
||||
|
||||
/**
|
||||
* Represents a group of {@link Node}s that are connected together.
|
||||
*
|
||||
* @author Branislav Stojkovic
|
||||
*/
|
||||
public class Group implements Comparable<Group> {
|
||||
|
||||
private Set<Node> nodes = new HashSet<Node>();
|
||||
|
||||
public Group() {
|
||||
|
||||
}
|
||||
|
||||
public Group(Node node1, Node node2) {
|
||||
nodes.add(node1);
|
||||
nodes.add(node2);
|
||||
}
|
||||
|
||||
public Group connect(IDIYComponent<?> component, int index) {
|
||||
getNodes().add(new Node(component, index));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Set<Node> getNodes() {
|
||||
return nodes;
|
||||
}
|
||||
|
||||
public List<Node> getSortedNodes() {
|
||||
List<Node> list = new ArrayList<Node>(nodes);
|
||||
Collections.sort(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((nodes == null) ? 0 : nodes.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
Group other = (Group) obj;
|
||||
if (nodes == null) {
|
||||
if (other.nodes != null)
|
||||
return false;
|
||||
} else if (!nodes.equals(other.nodes))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
List<Node> list = getSortedNodes();
|
||||
for (Node n : list) {
|
||||
if (sb.length() > 0)
|
||||
sb.append(" <-> ");
|
||||
sb.append(n);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Group o) {
|
||||
return toString().compareToIgnoreCase(o.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Group clone() {
|
||||
Group g = new Group();
|
||||
g.nodes.addAll(nodes);
|
||||
return g;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2018 held jointly by the individual authors.
|
||||
|
||||
This file is part of DIYLC.
|
||||
|
||||
DIYLC is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DIYLC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package org.diylc.netlist;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ITree {
|
||||
|
||||
List<ITree> getChildren();
|
||||
|
||||
TreeConnectionType getConnectionType();
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2018 held jointly by the individual authors.
|
||||
|
||||
This file is part of DIYLC.
|
||||
|
||||
DIYLC is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DIYLC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package org.diylc.netlist;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class Netlist implements Comparable<Netlist> {
|
||||
|
||||
private Set<Group> groups = new HashSet<Group>();
|
||||
private List<SwitchSetup> switchSetup = new ArrayList<SwitchSetup>();
|
||||
|
||||
public Netlist() {
|
||||
}
|
||||
|
||||
public Set<Group> getGroups() {
|
||||
return groups;
|
||||
}
|
||||
|
||||
public Netlist add(Group g) {
|
||||
groups.add(g);
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<Group> getSortedGroups() {
|
||||
List<Group> list = new ArrayList<Group>(groups);
|
||||
Collections.sort(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
public List<SwitchSetup> getSwitchSetup() {
|
||||
return switchSetup;
|
||||
}
|
||||
|
||||
public void done() {
|
||||
Collections.sort(switchSetup);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((groups == null) ? 0 : groups.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
Netlist other = (Netlist) obj;
|
||||
if (groups == null) {
|
||||
if (other.groups != null)
|
||||
return false;
|
||||
} else if (!groups.equals(other.groups))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
List<Group> list = getSortedGroups();
|
||||
for (Group g : list) {
|
||||
sb.append("\t").append(g).append("\n");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Netlist o) {
|
||||
return switchSetup.toString().compareToIgnoreCase(o.switchSetup.toString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,496 @@
|
||||
/*
|
||||
*
|
||||
* DIY Layout Creator (DIYLC). Copyright (c) 2009-2018 held jointly by the individual authors.
|
||||
*
|
||||
* This file is part of DIYLC.
|
||||
*
|
||||
* DIYLC is free software: you can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* DIYLC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with DIYLC. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.diylc.netlist;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.diylc.core.IDIYComponent;
|
||||
|
||||
public abstract class NetlistAnalyzer {
|
||||
|
||||
public NetlistAnalyzer() {}
|
||||
|
||||
public List<Summary> summarize(List<Netlist> netlists, Node preferredOutput) throws TreeException {
|
||||
Map<String, Summary> summaries = new HashMap<String, Summary>();
|
||||
for (Netlist n : netlists) {
|
||||
Summary s = summarize(n, preferredOutput);
|
||||
if (summaries.containsKey(s.getSummary()))
|
||||
summaries.get(s.getSummary()).append(n);
|
||||
else
|
||||
summaries.put(s.getSummary(), s);
|
||||
}
|
||||
|
||||
List<Summary> res = new ArrayList<Summary>(summaries.values());
|
||||
Collections.sort(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
protected abstract Summary summarize(Netlist netlist, Node preferredOutput) throws TreeException;
|
||||
|
||||
public Tree constructTreeBetween(Netlist netlist, Node nodeA, Node nodeB) {
|
||||
Tree tree = new Tree(TreeConnectionType.Parallel);
|
||||
connectNodes(netlist, nodeA, nodeB, tree.getChildren(), new Tree(TreeConnectionType.Series), new HashSet<Node>());
|
||||
|
||||
// System.out.println(netlist.getSwitchSetup());
|
||||
// System.out.println(tree);
|
||||
//
|
||||
// System.out.println("opposite:");
|
||||
// Tree tree1 = new Tree(TreeConnectionType.Parallel);
|
||||
// connectNodes(netlist, nodeB, nodeA, tree1.getChildren(), new Tree(TreeConnectionType.Series),
|
||||
// new HashSet<Node>());
|
||||
// System.out.println(tree1);
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
protected void connectNodes(Netlist netlist, Node nodeA, Node nodeB, List<Tree> concurrentPaths, Tree currentPath,
|
||||
Set<Node> visited) {
|
||||
if (nodeA == nodeB) {
|
||||
concurrentPaths.add(currentPath);
|
||||
return;
|
||||
}
|
||||
|
||||
Group groupA = findGroup(netlist, nodeA);
|
||||
|
||||
if (groupA == null)
|
||||
return;
|
||||
|
||||
if (groupA.getNodes().contains(nodeB)) {
|
||||
concurrentPaths.add(currentPath);
|
||||
return;
|
||||
}
|
||||
|
||||
visited.addAll(groupA.getNodes());
|
||||
|
||||
List<Tree> newConcurrentPaths = new ArrayList<Tree>();
|
||||
|
||||
for (Node n : groupA.getNodes()) {
|
||||
IDIYComponent<?> c = n.getComponent();
|
||||
for (int i = 0; i < c.getControlPointCount(); i++) {
|
||||
if (i != n.getPointIndex() && c.getInternalLinkName(i, n.getPointIndex()) != null) {
|
||||
TreeLeaf l = new TreeLeaf(c, i, n.getPointIndex());
|
||||
Node newNodeA = new Node(c, i);
|
||||
if (!visited.contains(newNodeA)) {
|
||||
// visited.add(n);
|
||||
Tree newCurrentPath = null;
|
||||
try {
|
||||
newCurrentPath = (Tree) currentPath.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
}
|
||||
Tree newItem = new Tree(l);
|
||||
if (!newCurrentPath.getChildren().contains(newItem))
|
||||
newCurrentPath.getChildren().add(newItem);
|
||||
// if (!currentPath.contains(l))
|
||||
// newCurrentPath.add(l);
|
||||
Set<Node> newVisited = new HashSet<Node>(visited);
|
||||
connectNodes(netlist, newNodeA, nodeB, newConcurrentPaths, newCurrentPath, newVisited);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (newConcurrentPaths.size() == 0)
|
||||
return;
|
||||
|
||||
|
||||
if (newConcurrentPaths.size() == 1) {
|
||||
if (newConcurrentPaths.get(0).getConnectionType() == TreeConnectionType.Series) {
|
||||
currentPath.getChildren().clear();
|
||||
currentPath.getChildren().addAll(newConcurrentPaths.get(0).getChildren());
|
||||
} else {
|
||||
currentPath.getChildren().add(newConcurrentPaths.get(0));
|
||||
}
|
||||
concurrentPaths.add(currentPath);
|
||||
return;
|
||||
}
|
||||
|
||||
mergePaths(newConcurrentPaths, false);
|
||||
concurrentPaths.addAll(newConcurrentPaths);
|
||||
}
|
||||
|
||||
protected void mergePaths(List<Tree> paths, boolean backward) {
|
||||
Map<Tree, Integer> uniques = new HashMap<Tree, Integer>();
|
||||
for (Tree t : paths) {
|
||||
if (t.getConnectionType() != TreeConnectionType.Series)
|
||||
continue;
|
||||
Tree key = t.getChildren().get(backward ? t.getChildren().size() - 1 : 0);
|
||||
Integer count = uniques.get(key);
|
||||
uniques.put(key, count == null ? 1 : count + 1);
|
||||
}
|
||||
|
||||
List<Tree> unmerged = new ArrayList<Tree>(paths);
|
||||
|
||||
for (Map.Entry<Tree, Integer> e : uniques.entrySet()) {
|
||||
if (e.getValue() > 1) {
|
||||
List<Tree> pathsToMerge = new ArrayList<Tree>();
|
||||
for (Tree t : paths) {
|
||||
Tree key = t.getChildren().get(backward ? t.getChildren().size() - 1 : 0);
|
||||
if (key.equals(e.getKey()))
|
||||
pathsToMerge.add(t);
|
||||
}
|
||||
unmerged.removeAll(pathsToMerge);
|
||||
|
||||
Tree jointStart = new Tree(new ArrayList<Tree>(), TreeConnectionType.Series);
|
||||
Tree jointFinish = new Tree(new ArrayList<Tree>(), TreeConnectionType.Series);
|
||||
|
||||
Tree unique = e.getKey();
|
||||
|
||||
for (int i = 0; i < pathsToMerge.get(0).getChildren().size(); i++) {
|
||||
boolean canMerge = true;
|
||||
unique = pathsToMerge.get(0).getChildren().get(backward ? pathsToMerge.get(0).getChildren().size() - i - 1 : i);
|
||||
for (Tree t : pathsToMerge) {
|
||||
if (t.getChildren().size() <= i || !t.getChildren().get(backward ? t.getChildren().size() - i - 1 : i).equals(unique)) {
|
||||
canMerge = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (canMerge)
|
||||
(backward ? jointFinish : jointStart).getChildren().add(unique);
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i = 0; i < pathsToMerge.get(0).getChildren().size(); i++) {
|
||||
boolean canMerge = true;
|
||||
unique = pathsToMerge.get(0).getChildren().get(backward ? i : pathsToMerge.get(0).getChildren().size() - i - 1);
|
||||
for (Tree t : pathsToMerge) {
|
||||
if (t.getChildren().size() <= i || !t.getChildren().get(backward ? 0 : t.getChildren().size() - 1).equals(unique)) {
|
||||
canMerge = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (canMerge)
|
||||
(backward ? jointStart : jointFinish).getChildren().add(unique);
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (!jointStart.getChildren().isEmpty() || !jointFinish.getChildren().isEmpty()) {
|
||||
Tree mergedTree = new Tree(new ArrayList<Tree>(), TreeConnectionType.Series);
|
||||
Tree parallelSection = new Tree(new ArrayList<Tree>(pathsToMerge), TreeConnectionType.Parallel);
|
||||
if (!jointStart.getChildren().isEmpty()) {
|
||||
mergedTree.getChildren().add(jointStart);
|
||||
for (Tree t : parallelSection.getChildren()) {
|
||||
t.trimChildrenLeft(jointStart.getChildren().size());
|
||||
}
|
||||
}
|
||||
mergedTree.getChildren().add(parallelSection);
|
||||
if (!jointFinish.getChildren().isEmpty()) {
|
||||
mergedTree.getChildren().add(jointFinish);
|
||||
for (Tree t : parallelSection.getChildren()) {
|
||||
t.trimChildrenRight(jointFinish.getChildren().size());
|
||||
}
|
||||
}
|
||||
paths.removeAll(pathsToMerge);
|
||||
paths.add(mergedTree);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// try in the opposite direction for paths we haven't merged
|
||||
if (!backward && !unmerged.isEmpty()) {
|
||||
paths.removeAll(unmerged);
|
||||
mergePaths(unmerged, true);
|
||||
paths.addAll(unmerged);
|
||||
}
|
||||
}
|
||||
//
|
||||
// protected void findAllPaths(Netlist netlist, Node nodeA, Node nodeB, List<TreeLeaf> currentPath,
|
||||
// List<List<TreeLeaf>> allPaths, Set<Node> visited) {
|
||||
// if (nodeA == nodeB) {
|
||||
// allPaths.add(currentPath);
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// // System.out.println("Finding path between " + nodeA + " and " + nodeB);
|
||||
//
|
||||
// Group groupA = findGroup(netlist, nodeA);
|
||||
//
|
||||
// if (groupA == null)
|
||||
// return;
|
||||
//
|
||||
// if (groupA.getNodes().contains(nodeB)) {
|
||||
// allPaths.add(currentPath);
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// for (Node n : groupA.getNodes()) {
|
||||
// IDIYComponent<?> c = n.getComponent();
|
||||
// for (int i = 0; i < c.getControlPointCount(); i++) {
|
||||
// if (i != n.getPointIndex() && c.getInternalLinkName(i, n.getPointIndex()) != null) {
|
||||
// TreeLeaf l = new TreeLeaf(c, i, n.getPointIndex());
|
||||
// Node newNodeA = new Node(c, i);
|
||||
// if (!visited.contains(newNodeA)) {
|
||||
// List<TreeLeaf> newCurrentPath = new ArrayList<TreeLeaf>(currentPath);
|
||||
// if (!currentPath.contains(l))
|
||||
// newCurrentPath.add(l);
|
||||
// Set<Node> newVisited = new HashSet<Node>(visited);
|
||||
// newVisited.add(nodeA);
|
||||
// newVisited.add(newNodeA);
|
||||
// findAllPaths(netlist, newNodeA, nodeB, newCurrentPath, allPaths, newVisited);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
protected Group findGroup(Netlist netlist, Node node) {
|
||||
for (Group g : netlist.getGroups())
|
||||
if (g.getNodes().contains(node))
|
||||
return g;
|
||||
return null;
|
||||
}
|
||||
|
||||
// protected List<Group> trace(Set<String> typeNames, String nodeName, Netlist netlist) {
|
||||
// List<Group> res = new ArrayList<Group>();
|
||||
// for (Group g : netlist.getGroups()) {
|
||||
// for (Node n : g.getNodes()) {
|
||||
// if (typeNames.contains(n.getComponent().getClass().getCanonicalName())
|
||||
// && (nodeName == null || n.getDisplayName().equalsIgnoreCase(nodeName))) {
|
||||
// res.add(g);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return res;
|
||||
// }
|
||||
|
||||
// protected List<Node> find(Set<String> typeNames, String nodeName, Group group) {
|
||||
// List<Node> res = new ArrayList<Node>();
|
||||
//
|
||||
// for (Node n : group.getNodes()) {
|
||||
// if (typeNames.contains(n.getComponent().getClass().getCanonicalName())
|
||||
// && (nodeName == null || n.getDisplayName().equalsIgnoreCase(nodeName))) {
|
||||
// res.add(n);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return res;
|
||||
// }
|
||||
|
||||
// protected List<Group> findGroups(Set<String> typeNames, String nodeName, Netlist netlist) {
|
||||
// List<Group> res = new ArrayList<Group>();
|
||||
// for (Group g : netlist.getGroups()) {
|
||||
// for (Node n : g.getNodes()) {
|
||||
// if (typeNames.contains(n.getComponent().getClass().getCanonicalName())
|
||||
// && (nodeName == null || n.getDisplayName().equalsIgnoreCase(nodeName))) {
|
||||
// res.add(g);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return res;
|
||||
// }
|
||||
|
||||
// protected List<Group> findGroups(Set<String> typeNames, String nodeName, Netlist netlist,
|
||||
// Collection<IDIYComponent<?>> belongTo) {
|
||||
// List<Group> res = new ArrayList<Group>();
|
||||
// for (Group g : netlist.getGroups()) {
|
||||
// for (Node n : g.getNodes()) {
|
||||
// if ((belongTo == null || belongTo.contains(n.getComponent()))
|
||||
// && (typeNames.contains(n.getComponent().getClass().getCanonicalName()))
|
||||
// && (nodeName == null || n.getDisplayName().equalsIgnoreCase(nodeName))) {
|
||||
// res.add(g);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return res;
|
||||
// }
|
||||
|
||||
protected List<Node> find(Set<String> typeNames, String nodeName, Netlist netlist) {
|
||||
List<Node> res = new ArrayList<Node>();
|
||||
for (Group g : netlist.getGroups()) {
|
||||
for (Node n : g.getNodes()) {
|
||||
if (typeNames.contains(n.getComponent().getClass().getCanonicalName())
|
||||
&& (nodeName == null || n.getDisplayName().equalsIgnoreCase(nodeName))) {
|
||||
res.add(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// protected List<Node> find(Set<String> typeNames, String nodeName, Netlist netlist, List<Node> inGroupWith) {
|
||||
// List<Node> res = new ArrayList<Node>();
|
||||
// for (Group g : netlist.getGroups()) {
|
||||
//
|
||||
// boolean inGroup;
|
||||
// if (inGroupWith == null) {
|
||||
// inGroup = true;
|
||||
// } else {
|
||||
// inGroup = true;
|
||||
// for (Node n1 : inGroupWith)
|
||||
// if (!g.getNodes().contains(n1)) {
|
||||
// inGroup = false;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// for (Node n : g.getNodes()) {
|
||||
// if (inGroup && typeNames.contains(n.getComponent().getClass().getCanonicalName())
|
||||
// && (nodeName == null || n.getDisplayName().equalsIgnoreCase(nodeName))) {
|
||||
// res.add(n);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return res;
|
||||
// }
|
||||
|
||||
// protected List<Node> find(Set<String> typeNames, String nodeName, Netlist netlist,
|
||||
// Collection<IDIYComponent<?>> belongTo) {
|
||||
// List<Node> res = new ArrayList<Node>();
|
||||
// for (Group g : netlist.getGroups()) {
|
||||
//
|
||||
// for (Node n : g.getNodes()) {
|
||||
// if ((belongTo == null || belongTo.contains(n.getComponent()))
|
||||
// && typeNames.contains(n.getComponent().getClass().getCanonicalName())
|
||||
// && (nodeName == null || n.getDisplayName().equalsIgnoreCase(nodeName))) {
|
||||
// res.add(n);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return res;
|
||||
// }
|
||||
|
||||
// protected boolean allMatch(Collection<Node> nodes, String name) {
|
||||
// for (Node n : nodes)
|
||||
// if (!n.getDisplayName().equalsIgnoreCase(name))
|
||||
// return false;
|
||||
//
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// protected boolean allComponentsMatch(Collection<Node> nodes, Set<IDIYComponent<?>> components) {
|
||||
// Set<IDIYComponent<?>> extracted = extractComponents(nodes);
|
||||
// return extracted.containsAll(components);
|
||||
// }
|
||||
//
|
||||
// protected Set<IDIYComponent<?>> extractComponents(Collection<Node> nodes) {
|
||||
// Set<IDIYComponent<?>> components = new HashSet<IDIYComponent<?>>();
|
||||
// for (Node n : nodes)
|
||||
// components.add(n.getComponent());
|
||||
// return components;
|
||||
// }
|
||||
|
||||
protected String extractName(IDIYComponent<?> c) {
|
||||
return c.getName() + " " + c.getValueForDisplay();
|
||||
}
|
||||
|
||||
public static List<Set<IDIYComponent<?>>> extractComponentGroups(List<Netlist> netlists) {
|
||||
List<Set<IDIYComponent<?>>> res = new ArrayList<Set<IDIYComponent<?>>>();
|
||||
for (Netlist n : netlists) {
|
||||
res.addAll(extractComponentGroups(n));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public static List<Set<IDIYComponent<?>>> extractComponentGroups(Netlist netlist) {
|
||||
List<Set<IDIYComponent<?>>> res = new ArrayList<Set<IDIYComponent<?>>>();
|
||||
for (Group g : netlist.getGroups()) {
|
||||
Set<IDIYComponent<?>> components = new HashSet<IDIYComponent<?>>();
|
||||
for (Node n : g.getNodes())
|
||||
components.add(n.getComponent());
|
||||
res.add(components);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public static Set<IDIYComponent<?>> extractComponents(Netlist netlist) {
|
||||
Set<IDIYComponent<?>> res = new HashSet<IDIYComponent<?>>();
|
||||
for (Group g : netlist.getGroups())
|
||||
for (Node n : g.getNodes())
|
||||
res.add(n.getComponent());
|
||||
return res;
|
||||
}
|
||||
|
||||
protected int find(Node node, List<Group> groups) {
|
||||
for (int i = 0; i < groups.size(); i++)
|
||||
if (groups.get(i).getNodes().contains(node))
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// protected List<String> extractNames(Collection<IDIYComponent<?>> components) {
|
||||
// List<String> names = new ArrayList<String>();
|
||||
// for (IDIYComponent<?> c : components)
|
||||
// names.add(c.getName() + " " + c.getValueForDisplay());
|
||||
// Collections.sort(names);
|
||||
// return names;
|
||||
// }
|
||||
//
|
||||
// protected Netlist simplify(Netlist netlist, Set<Node> nodesToMerge, Collection<Node> nodesToPurge) {
|
||||
// Netlist res = new Netlist();
|
||||
// res.getSwitchSetup().addAll(netlist.getSwitchSetup());
|
||||
//
|
||||
// Group merged = new Group();
|
||||
//
|
||||
// // merge
|
||||
// for (Group g : netlist.getGroups()) {
|
||||
// boolean needsMerging = false;
|
||||
// for (Node n : nodesToMerge) {
|
||||
// if (g.getNodes().contains(n)) {
|
||||
// needsMerging = true;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// if (needsMerging) {
|
||||
// for (Node n : g.getNodes()) {
|
||||
// if (!nodesToMerge.contains(n))
|
||||
// merged.getNodes().add(n);
|
||||
// }
|
||||
// } else {
|
||||
// res.getGroups().add(g.clone());
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (!merged.getNodes().isEmpty())
|
||||
// res.getGroups().add(merged);
|
||||
//
|
||||
// // purge
|
||||
// for (Group g : res.getGroups()) {
|
||||
// g.getNodes().removeAll(nodesToPurge);
|
||||
// }
|
||||
//
|
||||
// System.out.println("Before:\n" + netlist);
|
||||
// System.out.println("After:\n" + res);
|
||||
//
|
||||
// return res;
|
||||
// }
|
||||
//
|
||||
protected boolean intersect(List<Group> groups, Node node) {
|
||||
for (Group g : groups)
|
||||
if (g.getNodes().contains(node))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
protected Node intersect(List<Group> groups, Group group) {
|
||||
for (Group g : groups)
|
||||
for (Node node : group.getNodes())
|
||||
if (g.getNodes().contains(node))
|
||||
return node;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2018 held jointly by the individual authors.
|
||||
|
||||
This file is part of DIYLC.
|
||||
|
||||
DIYLC is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DIYLC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package org.diylc.netlist;
|
||||
|
||||
import org.diylc.core.IDIYComponent;
|
||||
|
||||
/**
|
||||
* Represents a single node in a {@link Netlist}, uniquely defined by a component and a control point.
|
||||
*
|
||||
* @author Branislav Stojkovic
|
||||
*/
|
||||
public class Node implements Comparable<Node> {
|
||||
|
||||
private IDIYComponent<?> component;
|
||||
private int pointIndex;
|
||||
|
||||
public Node(IDIYComponent<?> component, int pointIndex) {
|
||||
super();
|
||||
this.component = component;
|
||||
this.pointIndex = pointIndex;
|
||||
}
|
||||
|
||||
public IDIYComponent<?> getComponent() {
|
||||
return component;
|
||||
}
|
||||
|
||||
public int getPointIndex() {
|
||||
return pointIndex;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
String[] section = component.getSectionNames(pointIndex);
|
||||
return (section == null || section.length > 1 ? "" : section[0] + ".") + component.getControlPointNodeName(pointIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((component == null) ? 0 : component.hashCode());
|
||||
result = prime * result + pointIndex;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
Node other = (Node) obj;
|
||||
if (component == null) {
|
||||
if (other.component != null)
|
||||
return false;
|
||||
} else if (!component.equals(other.component))
|
||||
return false;
|
||||
if (pointIndex != other.pointIndex)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (component.getControlPointCount() == 1)
|
||||
return component.getName();
|
||||
return component.getName() + "." + getDisplayName() /*+ " @ (" + component.getControlPoint(pointIndex).getX() + ":" + component.getControlPoint(pointIndex).getY() + ")"*/;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Node o) {
|
||||
return toString().compareToIgnoreCase(o.toString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2018 held jointly by the individual authors.
|
||||
|
||||
This file is part of DIYLC.
|
||||
|
||||
DIYLC is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DIYLC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package org.diylc.netlist;
|
||||
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.ISwitch;
|
||||
|
||||
/**
|
||||
* Represents a single position of a switch, uniquely defined by the switch and the position.
|
||||
*
|
||||
* @author Branislav Stojkovic
|
||||
*/
|
||||
public class Position implements Comparable<Position> {
|
||||
|
||||
private ISwitch theSwitch;
|
||||
private int position;
|
||||
|
||||
public Position(ISwitch theSwitch, int position) {
|
||||
super();
|
||||
this.theSwitch = theSwitch;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public ISwitch getSwitch() {
|
||||
return theSwitch;
|
||||
}
|
||||
|
||||
public int getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + position;
|
||||
result = prime * result + ((theSwitch == null) ? 0 : theSwitch.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
Position other = (Position) obj;
|
||||
if (position != other.position)
|
||||
return false;
|
||||
if (theSwitch == null) {
|
||||
if (other.theSwitch != null)
|
||||
return false;
|
||||
} else if (!theSwitch.equals(other.theSwitch))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return (theSwitch instanceof IDIYComponent<?> ? ((IDIYComponent<?>) theSwitch).getName() + "." : "") + theSwitch.getPositionName(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Position o) {
|
||||
if (theSwitch instanceof IDIYComponent<?> && o.theSwitch instanceof IDIYComponent<?>)
|
||||
return ((IDIYComponent<?>) theSwitch).getName().compareToIgnoreCase(((IDIYComponent<?>) o.theSwitch).getName());
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2018 held jointly by the individual authors.
|
||||
|
||||
This file is part of DIYLC.
|
||||
|
||||
DIYLC is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DIYLC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package org.diylc.netlist;
|
||||
|
||||
public class Summary implements Comparable<Summary> {
|
||||
|
||||
private Netlist netlist;
|
||||
private String summary;
|
||||
|
||||
public Summary(Netlist netlist, String summary) {
|
||||
super();
|
||||
this.netlist = netlist;
|
||||
this.summary = summary;
|
||||
}
|
||||
|
||||
public Netlist getNetlist() {
|
||||
return netlist;
|
||||
}
|
||||
|
||||
public void append(Netlist netlist) {
|
||||
this.netlist.getSwitchSetup().addAll(netlist.getSwitchSetup());
|
||||
}
|
||||
|
||||
public String getSummary() {
|
||||
return summary;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((netlist == null) ? 0 : netlist.hashCode());
|
||||
result = prime * result + ((summary == null) ? 0 : summary.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
Summary other = (Summary) obj;
|
||||
if (netlist == null) {
|
||||
if (other.netlist != null)
|
||||
return false;
|
||||
} else if (!netlist.equals(other.netlist))
|
||||
return false;
|
||||
if (summary == null) {
|
||||
if (other.summary != null)
|
||||
return false;
|
||||
} else if (!summary.equals(other.summary))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return summary.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Summary o) {
|
||||
return netlist.compareTo(o.netlist);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2018 held jointly by the individual authors.
|
||||
|
||||
This file is part of DIYLC.
|
||||
|
||||
DIYLC is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DIYLC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package org.diylc.netlist;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents a full switch configuration of the whole {@link Netlist}, containing one position of each switch in the {@link Netlist}.
|
||||
*
|
||||
* @author Branislav Stojkovic
|
||||
*/
|
||||
public class SwitchSetup implements Comparable<SwitchSetup> {
|
||||
|
||||
private List<Position> positions;
|
||||
|
||||
public SwitchSetup(List<Position> positions) {
|
||||
super();
|
||||
this.positions = positions;
|
||||
Collections.sort(this.positions);
|
||||
}
|
||||
|
||||
public List<Position> getPositions() {
|
||||
return positions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((positions == null) ? 0 : positions.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
SwitchSetup other = (SwitchSetup) obj;
|
||||
if (positions == null) {
|
||||
if (other.positions != null)
|
||||
return false;
|
||||
} else if (!positions.equals(other.positions))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Position s : positions)
|
||||
{
|
||||
if (sb.length() > 0)
|
||||
sb.append(":");
|
||||
sb.append(s.toString());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(SwitchSetup o) {
|
||||
return toString().compareToIgnoreCase(o.toString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,309 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2018 held jointly by the individual authors.
|
||||
|
||||
This file is part of DIYLC.
|
||||
|
||||
DIYLC is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DIYLC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package org.diylc.netlist;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.diylc.core.IDIYComponent;
|
||||
|
||||
public class Tree {
|
||||
|
||||
private List<Tree> children;
|
||||
private TreeConnectionType connectionType;
|
||||
private TreeLeaf leaf;
|
||||
|
||||
public Tree(TreeConnectionType connectionType) {
|
||||
this.children = new ArrayList<Tree>();
|
||||
this.connectionType = connectionType;
|
||||
}
|
||||
|
||||
public Tree(TreeLeaf leaf) {
|
||||
this.leaf = leaf;
|
||||
}
|
||||
|
||||
public Tree(List<Tree> children, TreeConnectionType connectionType) {
|
||||
this.children = children;
|
||||
this.connectionType = connectionType;
|
||||
}
|
||||
|
||||
public List<Tree> getChildren() {
|
||||
return children;
|
||||
}
|
||||
|
||||
public void trimChildrenLeft(int count) {
|
||||
children = children.subList(count, children.size());
|
||||
}
|
||||
|
||||
public void trimChildrenRight(int count) {
|
||||
children = children.subList(0, children.size() - count);
|
||||
}
|
||||
|
||||
public TreeConnectionType getConnectionType() {
|
||||
return connectionType;
|
||||
}
|
||||
|
||||
public TreeLeaf getLeaf() {
|
||||
return leaf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((children == null) ? 0 : children.hashCode());
|
||||
result = prime * result + ((connectionType == null) ? 0 : connectionType.hashCode());
|
||||
result = prime * result + ((leaf == null) ? 0 : leaf.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
Tree other = (Tree) obj;
|
||||
if (children == null) {
|
||||
if (other.children != null)
|
||||
return false;
|
||||
} else if (!children.equals(other.children))
|
||||
return false;
|
||||
if (connectionType != other.connectionType)
|
||||
return false;
|
||||
if (leaf == null) {
|
||||
if (other.leaf != null)
|
||||
return false;
|
||||
} else if (!leaf.equals(other.leaf))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private List<Tree> getOrderedChildren() {
|
||||
if (getConnectionType() == TreeConnectionType.Series)
|
||||
return children;
|
||||
List<Tree> ordered = new ArrayList<Tree>(children);
|
||||
Collections.sort(ordered, new Comparator<Tree>() {
|
||||
|
||||
@Override
|
||||
public int compare(Tree o1, Tree o2) {
|
||||
return o1.toString().compareToIgnoreCase(o2.toString());
|
||||
}});
|
||||
return ordered;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (leaf != null)
|
||||
return leaf.toString();
|
||||
|
||||
StringBuilder sb = new StringBuilder("(");
|
||||
boolean first = true;
|
||||
for(Tree child : getOrderedChildren()) {
|
||||
if (!first)
|
||||
sb.append(" " ).append(connectionType).append(" ");
|
||||
first = false;
|
||||
sb.append(child);
|
||||
}
|
||||
sb.append(")");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String toHTML(int depth) {
|
||||
if (leaf != null)
|
||||
return leaf.toHTML();
|
||||
|
||||
List<Tree> children = getOrderedChildren();
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (depth > 0 && children.size() > 1)
|
||||
sb.append("(");
|
||||
boolean first = true;
|
||||
for(Tree child : children) {
|
||||
if (!first) {
|
||||
sb.append(" ").append(connectionType.toHTML()).append(" ");
|
||||
if (depth == 0)
|
||||
sb.append("<br>");
|
||||
}
|
||||
first = false;
|
||||
sb.append(child.toHTML(depth + children.size() > 1 ? 1 : 0));
|
||||
}
|
||||
if (depth > 0 && children.size() > 1)
|
||||
sb.append(")");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object clone() throws CloneNotSupportedException {
|
||||
if (leaf != null)
|
||||
return new Tree(leaf);
|
||||
List<Tree> newChildren = new ArrayList<Tree>();
|
||||
for (Tree t : children)
|
||||
newChildren.add((Tree) t.clone());
|
||||
return new Tree(newChildren, connectionType);
|
||||
}
|
||||
|
||||
public Tree filter(Set<String> types) {
|
||||
if (leaf != null) {
|
||||
if (types.contains(leaf.getComponent().getClass().getCanonicalName()))
|
||||
return new Tree(leaf);
|
||||
return null;
|
||||
}
|
||||
List<Tree> newChildren = new ArrayList<Tree>();
|
||||
for (Tree t : children) {
|
||||
Tree child = t.filter(types);
|
||||
if (child != null)
|
||||
newChildren.add(child);
|
||||
}
|
||||
if (newChildren.isEmpty())
|
||||
return null;
|
||||
return new Tree(newChildren, connectionType);
|
||||
}
|
||||
|
||||
public void walk(ITreeWalker walker) {
|
||||
if (leaf != null) {
|
||||
walker.visit(leaf);
|
||||
} else {
|
||||
for (Tree t : children) {
|
||||
walker.visit(t);
|
||||
t.walk(walker);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Set<IDIYComponent<?>> extractComponents(Set<String> types) {
|
||||
Set<IDIYComponent<?>> res = new HashSet<IDIYComponent<?>>();
|
||||
if (leaf != null && types.contains(leaf.getComponent().getClass().getCanonicalName())) {
|
||||
res.add(leaf.getComponent());
|
||||
} else if (children != null) {
|
||||
for (Tree t : children) {
|
||||
Set<IDIYComponent<?>> childRes = t.extractComponents(types);
|
||||
if (childRes != null)
|
||||
res.addAll(childRes);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public Tree locate(TreeLeaf l, boolean forceDirection) {
|
||||
if (leaf != null && leaf.equals(l, forceDirection))
|
||||
return this;
|
||||
if (children != null) {
|
||||
for (Tree t : children) {
|
||||
Tree childL = t.locate(l, forceDirection);
|
||||
if (childL != null) {
|
||||
// if (t.getLeaf() != null)
|
||||
// return this;
|
||||
return childL;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Tree findCommonParent(Tree t1, Tree t2) {
|
||||
if (t1 == null)
|
||||
return t2;
|
||||
if (t2 == null)
|
||||
return t1;
|
||||
|
||||
if (children == null)
|
||||
return null;
|
||||
|
||||
if (!this.contains(t1) || !this.contains(t2))
|
||||
return null;
|
||||
|
||||
Tree p1 = this;
|
||||
Tree p2 = this;
|
||||
for (Tree c : children) {
|
||||
if (c.contains(t1))
|
||||
p1 = c;
|
||||
if (c.contains(t2))
|
||||
p2 = c;
|
||||
}
|
||||
|
||||
if (p1 != p2 || p1 == this || p2 == this)
|
||||
return this;
|
||||
|
||||
return p1.findCommonParent(t1, t2);
|
||||
}
|
||||
|
||||
public Tree findCommonParent(List<Tree> t) {
|
||||
if (t.contains(null))
|
||||
{
|
||||
while(t.contains(null))
|
||||
t.remove(null);
|
||||
return findCommonParent(t);
|
||||
}
|
||||
|
||||
if (t.size() == 0)
|
||||
return null;
|
||||
if (t.size() == 1)
|
||||
return t.get(0);
|
||||
if (t.size() == 2)
|
||||
return findCommonParent(t.get(0), t.get(1));
|
||||
|
||||
List<Tree> remainder = t.subList(1, t.size());
|
||||
return findCommonParent(t.get(0), findCommonParent(remainder));
|
||||
}
|
||||
|
||||
public Tree findParent(Tree t) {
|
||||
if (children == null)
|
||||
return null;
|
||||
if (children.contains(t))
|
||||
return this;
|
||||
for (Tree c : children)
|
||||
{
|
||||
Tree p = c.findParent(t);
|
||||
if (p != null)
|
||||
return p;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean contains(Tree t) {
|
||||
if (this == t)
|
||||
return true;
|
||||
|
||||
if (children == null)
|
||||
return false;
|
||||
if (children.contains(t))
|
||||
return true;
|
||||
for (Tree c : children)
|
||||
if (c.contains(t))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public interface ITreeWalker {
|
||||
|
||||
void visit(Tree t);
|
||||
|
||||
void visit(TreeLeaf l);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2018 held jointly by the individual authors.
|
||||
|
||||
This file is part of DIYLC.
|
||||
|
||||
DIYLC is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DIYLC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package org.diylc.netlist;
|
||||
|
||||
public enum TreeConnectionType {
|
||||
|
||||
Series("+", "red"), Parallel("||", "blue");
|
||||
|
||||
private String label;
|
||||
private String color;
|
||||
|
||||
private TreeConnectionType(String label, String color) {
|
||||
this.label = label;
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public String toHTML() {
|
||||
return "<b><font color='" + color + "'>" + label + "</font></b>";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package org.diylc.netlist;
|
||||
|
||||
public class TreeException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public TreeException() {
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public TreeException(String message) {
|
||||
super(message);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public TreeException(Throwable cause) {
|
||||
super(cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public TreeException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2018 held jointly by the individual authors.
|
||||
|
||||
This file is part of DIYLC.
|
||||
|
||||
DIYLC is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DIYLC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package org.diylc.netlist;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.diylc.core.IDIYComponent;
|
||||
|
||||
public class TreeLeaf implements ITree {
|
||||
|
||||
private IDIYComponent<?> component;
|
||||
private int pointIndex1;
|
||||
private int pointIndex2;
|
||||
|
||||
public TreeLeaf(IDIYComponent<?> component, int pointIndex1, int pointIndex2) {
|
||||
this.component = component;
|
||||
this.pointIndex1 = pointIndex1;
|
||||
this.pointIndex2 = pointIndex2;
|
||||
}
|
||||
|
||||
public IDIYComponent<?> getComponent() {
|
||||
return component;
|
||||
}
|
||||
|
||||
public int getPointIndex1() {
|
||||
return pointIndex1;
|
||||
}
|
||||
|
||||
public int getPointIndex2() {
|
||||
return pointIndex2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ITree> getChildren() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TreeConnectionType getConnectionType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((component == null) ? 0 : component.hashCode());
|
||||
result = prime * result + pointIndex1;
|
||||
result = prime * result + pointIndex2;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
TreeLeaf other = (TreeLeaf) obj;
|
||||
if (component == null) {
|
||||
if (other.component != null)
|
||||
return false;
|
||||
} else if (!component.equals(other.component))
|
||||
return false;
|
||||
if (pointIndex1 != other.pointIndex1)
|
||||
return false;
|
||||
if (pointIndex2 != other.pointIndex2)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean equals(TreeLeaf other, boolean forceDirection) {
|
||||
if (component == null) {
|
||||
if (other.component != null)
|
||||
return false;
|
||||
} else if (!component.equals(other.component))
|
||||
return false;
|
||||
return (pointIndex1 == other.pointIndex1 && pointIndex2 == other.pointIndex2) || (!forceDirection && (pointIndex1 == other.pointIndex2 && pointIndex2 == other.pointIndex1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String linkName = component.getInternalLinkName(pointIndex1, pointIndex2);
|
||||
if (component.getName().equals(linkName))
|
||||
return linkName;
|
||||
return component.getName() + "." + linkName;
|
||||
}
|
||||
|
||||
public String toHTML() {
|
||||
return toString().replace("<", "<").replace(">", ">");
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,7 @@ public class CalcUtils {
|
||||
* @param x
|
||||
* @return
|
||||
*/
|
||||
public static int roundToGrid(int x, Size gridSpacing) {
|
||||
public static int roundToGrid(double x, Size gridSpacing) {
|
||||
double grid = gridSpacing.convertToPixels();
|
||||
return (int) (Math.round(1f * x / grid) * grid);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2018 held jointly by the individual authors.
|
||||
|
||||
This file is part of DIYLC.
|
||||
|
||||
DIYLC is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DIYLC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package org.diylc.presenter;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
import com.thoughtworks.xstream.converters.MarshallingContext;
|
||||
import com.thoughtworks.xstream.converters.UnmarshallingContext;
|
||||
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
|
||||
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
|
||||
|
||||
/**
|
||||
* Serializes {@link Color} objects as hex values instead of r/g/b. Backwards compatible when unmarshalling.
|
||||
*
|
||||
* @author Branislav Stojkovic
|
||||
*/
|
||||
public class ColorConverter extends com.thoughtworks.xstream.converters.extended.ColorConverter {
|
||||
|
||||
@Override
|
||||
public void marshal(Object object, HierarchicalStreamWriter writer, MarshallingContext context) {
|
||||
Color c = (Color) object;
|
||||
writer.addAttribute("hex", String.format("%02x%02x%02x", c.getRed(), c.getGreen(), c.getBlue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
|
||||
if (reader.getAttribute("hex") != null)
|
||||
return Color.decode("#" + reader.getAttribute("hex"));
|
||||
return super.unmarshal(reader, context);
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public boolean canConvert(Class clazz) {
|
||||
return Color.class.isAssignableFrom(clazz);
|
||||
}
|
||||
}
|
||||
@@ -92,13 +92,11 @@ public class ComponentProcessor {
|
||||
Icon icon;
|
||||
double zOrder;
|
||||
boolean flexibleZOrder;
|
||||
boolean stretchable;
|
||||
BomPolicy bomPolicy;
|
||||
boolean autoEdit;
|
||||
IComponentTransformer transformer;
|
||||
KeywordPolicy keywordPolicy;
|
||||
String keywordTag;
|
||||
boolean continuity;
|
||||
if (clazz.isAnnotationPresent(ComponentDescriptor.class)) {
|
||||
ComponentDescriptor annotation = clazz.getAnnotation(ComponentDescriptor.class);
|
||||
name = annotation.name();
|
||||
@@ -109,29 +107,13 @@ public class ComponentProcessor {
|
||||
author = annotation.author();
|
||||
zOrder = annotation.zOrder();
|
||||
flexibleZOrder = annotation.flexibleZOrder();
|
||||
stretchable = annotation.stretchable();
|
||||
bomPolicy = annotation.bomPolicy();
|
||||
autoEdit = annotation.autoEdit();
|
||||
transformer = getComponentTransformer(annotation.transformer());
|
||||
keywordPolicy = annotation.keywordPolicy();
|
||||
keywordTag = annotation.keywordTag();
|
||||
continuity = annotation.continuity();
|
||||
} else { // default
|
||||
name = clazz.getSimpleName();
|
||||
description = "";
|
||||
creationMethod = CreationMethod.SINGLE_CLICK;
|
||||
category = "Uncategorized";
|
||||
namePrefix = "Unknown";
|
||||
author = "Unknown";
|
||||
zOrder = IDIYComponent.COMPONENT;
|
||||
flexibleZOrder = false;
|
||||
stretchable = true;
|
||||
bomPolicy = BomPolicy.SHOW_ALL_NAMES;
|
||||
autoEdit = true;
|
||||
transformer = null;
|
||||
keywordPolicy = KeywordPolicy.NEVER_SHOW;
|
||||
keywordTag = null;
|
||||
continuity = false;
|
||||
return null;
|
||||
}
|
||||
icon = null;
|
||||
// Draw component icon.
|
||||
@@ -151,7 +133,7 @@ public class ComponentProcessor {
|
||||
}
|
||||
ComponentType componentType =
|
||||
new ComponentType(name, description, creationMethod, category, namePrefix, author, icon, clazz, zOrder,
|
||||
flexibleZOrder, stretchable, bomPolicy, autoEdit, transformer, keywordPolicy, keywordTag, continuity);
|
||||
flexibleZOrder, bomPolicy, autoEdit, transformer, keywordPolicy, keywordTag);
|
||||
componentTypeMap.put(clazz.getName(), componentType);
|
||||
return componentType;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package org.diylc.presenter;
|
||||
|
||||
import java.awt.geom.Point2D;
|
||||
|
||||
public class Connection {
|
||||
|
||||
private Point2D p1;
|
||||
private Point2D p2;
|
||||
|
||||
public Connection(Point2D p1, Point2D p2) {
|
||||
this.p1 = p1.getX() < p2.getX() || p1.getX() == p2.getX() && p1.getY() < p2.getY() ? p1 : p2;
|
||||
this.p2 = p1.getX() < p2.getX() || p1.getX() == p2.getX() && p1.getY() < p2.getY() ? p2 : p1;
|
||||
}
|
||||
|
||||
public Point2D getP1() {
|
||||
return p1;
|
||||
}
|
||||
|
||||
public Point2D getP2() {
|
||||
return p2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((p1 == null) ? 0 : p1.hashCode());
|
||||
result = prime * result + ((p2 == null) ? 0 : p2.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
Connection other = (Connection) obj;
|
||||
if (p1 == null) {
|
||||
if (other.p1 != null)
|
||||
return false;
|
||||
} else if (!p1.equals(other.p1))
|
||||
return false;
|
||||
if (p2 == null) {
|
||||
if (other.p2 != null)
|
||||
return false;
|
||||
} else if (!p2.equals(other.p2))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -26,12 +26,16 @@ import java.awt.Graphics2D;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Area;
|
||||
import java.awt.geom.Line2D;
|
||||
import java.awt.geom.Path2D;
|
||||
import java.awt.geom.PathIterator;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -39,7 +43,6 @@ import java.util.Set;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.diylc.appframework.miscutils.ConfigurationManager;
|
||||
import org.diylc.appframework.simplemq.MessageDispatcher;
|
||||
import org.diylc.common.ComponentType;
|
||||
import org.diylc.common.DrawOption;
|
||||
import org.diylc.common.EventType;
|
||||
import org.diylc.common.GridType;
|
||||
@@ -47,6 +50,7 @@ import org.diylc.common.IComponentFiler;
|
||||
import org.diylc.common.IPlugInPort;
|
||||
import org.diylc.common.ObjectCache;
|
||||
import org.diylc.core.ComponentState;
|
||||
import org.diylc.core.IContinuity;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.Project;
|
||||
import org.diylc.core.Theme;
|
||||
@@ -64,9 +68,12 @@ public class DrawingManager {
|
||||
private static final Logger LOG = Logger.getLogger(DrawingManager.class);
|
||||
|
||||
public static int CONTROL_POINT_SIZE = 7;
|
||||
public static double EXTRA_SPACE = 0.25;
|
||||
|
||||
public static final String ZOOM_KEY = "zoom";
|
||||
|
||||
private static boolean SHADE_EXTRA_SPACE = true;
|
||||
|
||||
public static String DEBUG_COMPONENT_AREAS = "org.diylc.debugComponentAreas";
|
||||
public static String DEBUG_CONTINUITY_AREAS = "org.diylc.debugContinuityAreas";
|
||||
|
||||
@@ -122,12 +129,13 @@ public class DrawingManager {
|
||||
* @param controlPointSlot
|
||||
* @param componentSlot
|
||||
* @param dragInProgress
|
||||
* @param externalZoom
|
||||
* @return
|
||||
*/
|
||||
public List<IDIYComponent<?>> drawProject(Graphics2D g2d, Project project, Set<DrawOption> drawOptions,
|
||||
IComponentFiler filter, Rectangle selectionRect, Collection<IDIYComponent<?>> selectedComponents,
|
||||
Set<IDIYComponent<?>> lockedComponents, Set<IDIYComponent<?>> groupedComponents, List<Point> controlPointSlot,
|
||||
List<IDIYComponent<?>> componentSlot, boolean dragInProgress) {
|
||||
List<IDIYComponent<?>> componentSlot, boolean dragInProgress, Double externalZoom) {
|
||||
failedComponents.clear();
|
||||
if (project == null) {
|
||||
return failedComponents;
|
||||
@@ -140,6 +148,9 @@ public class DrawingManager {
|
||||
zoom = 1 / Constants.PIXEL_SIZE;
|
||||
}
|
||||
|
||||
if (externalZoom != null)
|
||||
zoom *= externalZoom;
|
||||
|
||||
G2DWrapper g2dWrapper = new G2DWrapper(g2d, zoom);
|
||||
|
||||
if (drawOptions.contains(DrawOption.ANTIALIASING)) {
|
||||
@@ -166,7 +177,7 @@ public class DrawingManager {
|
||||
}
|
||||
|
||||
// AffineTransform initialTx = g2d.getTransform();
|
||||
Dimension d = getCanvasDimensions(project, zoom, true);
|
||||
Dimension d = getCanvasDimensions(project, zoom, drawOptions.contains(DrawOption.EXTRA_SPACE));
|
||||
|
||||
g2dWrapper.setColor(theme.getBgColor());
|
||||
g2dWrapper.fillRect(0, 0, d.width, d.height);
|
||||
@@ -175,23 +186,45 @@ public class DrawingManager {
|
||||
GridType gridType = GridType.LINES;
|
||||
if (drawOptions.contains(DrawOption.GRID) && gridType != GridType.NONE) {
|
||||
double zoomStep = project.getGridSpacing().convertToPixels() * zoom;
|
||||
float gridThickness = (float) (1f * (zoom > 1 ? 1 : zoom));
|
||||
if (gridType == GridType.CROSSHAIR) {
|
||||
g2d.setStroke(new BasicStroke(1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10f, new float[] {
|
||||
g2d.setStroke(new BasicStroke(gridThickness, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10f, new float[] {
|
||||
(float) zoomStep / 2, (float) zoomStep / 2}, (float) zoomStep / 4));
|
||||
} else if (gridType == GridType.DOT) {
|
||||
g2d.setStroke(new BasicStroke(1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10f, new float[] {1f,
|
||||
(float) zoomStep - 1}, 0f));
|
||||
g2d.setStroke(new BasicStroke(gridThickness, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10f, new float[] {
|
||||
1f, (float) zoomStep - 1}, 0f));
|
||||
} else {
|
||||
g2d.setStroke(ObjectCache.getInstance().fetchZoomableStroke(gridThickness));
|
||||
}
|
||||
|
||||
g2dWrapper.setColor(theme.getGridColor());
|
||||
for (double i = zoomStep; i < d.width; i += zoomStep) {
|
||||
g2dWrapper.drawLine((int) i, 0, (int) i, d.height - 1);
|
||||
g2dWrapper.draw(new Line2D.Double(i, 0, i, d.height - 1));
|
||||
}
|
||||
for (double j = zoomStep; j < d.height; j += zoomStep) {
|
||||
g2dWrapper.drawLine(0, (int) j, d.width - 1, (int) j);
|
||||
g2dWrapper.draw(new Line2D.Double(0, j, d.width - 1, j));
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle2D extraSpaceRect = null;
|
||||
AffineTransform extraSpaceTx = null;
|
||||
// manage extra space
|
||||
double extraSpace = 0;
|
||||
if (drawOptions.contains(DrawOption.EXTRA_SPACE)) {
|
||||
Dimension dInner = getCanvasDimensions(project, zoom, false);
|
||||
extraSpace = getExtraSpace(project) * zoom;
|
||||
float borderThickness = (float) (3f * (zoom > 1 ? 1 : zoom));
|
||||
g2d.setStroke(ObjectCache.getInstance().fetchStroke(borderThickness, new float[] {borderThickness * 4, borderThickness * 4, }, 0, BasicStroke.CAP_BUTT));
|
||||
g2dWrapper.setColor(theme.getOutlineColor());
|
||||
extraSpaceRect = new Rectangle2D.Double(extraSpace, extraSpace, dInner.getWidth(), dInner.getHeight());
|
||||
g2d.draw(extraSpaceRect);
|
||||
extraSpaceTx = g2d.getTransform();
|
||||
|
||||
// translate to the new (0, 0)
|
||||
g2d.transform(AffineTransform.getTranslateInstance(extraSpace, extraSpace));
|
||||
}
|
||||
|
||||
// apply zoom
|
||||
if (Math.abs(1.0 - zoom) > 1e-4) {
|
||||
g2dWrapper.scale(zoom, zoom);
|
||||
}
|
||||
@@ -232,6 +265,10 @@ public class DrawingManager {
|
||||
// Draw the component through the g2dWrapper.
|
||||
try {
|
||||
component.draw(g2dWrapper, state, drawOptions.contains(DrawOption.OUTLINE_MODE), project, g2dWrapper);
|
||||
if (g2dWrapper.isTrackingContinuityArea()) {
|
||||
LOG.info("Component " + component.getName() + " of type " + component.getClass().getName() + " did not stop tracking continuity area.");
|
||||
g2dWrapper.stopTrackingContinuityArea();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error drawing " + component.getName(), e);
|
||||
failedComponents.add(component);
|
||||
@@ -356,8 +393,8 @@ public class DrawingManager {
|
||||
}
|
||||
}
|
||||
|
||||
if (continuityArea != null && (ConfigurationManager.getInstance().readBoolean(IPlugInPort.HIGHLIGHT_CONTINUITY_AREA, false)))
|
||||
{
|
||||
if (continuityArea != null
|
||||
&& (ConfigurationManager.getInstance().readBoolean(IPlugInPort.HIGHLIGHT_CONTINUITY_AREA, false))) {
|
||||
Composite oldComposite = g2d.getComposite();
|
||||
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
|
||||
g2d.setColor(Color.green);
|
||||
@@ -365,6 +402,16 @@ public class DrawingManager {
|
||||
g2d.setComposite(oldComposite);
|
||||
}
|
||||
|
||||
// shade extra space
|
||||
if (SHADE_EXTRA_SPACE && extraSpaceRect != null) {
|
||||
Area extraSpaceArea = new Area(new Rectangle2D.Double(0, 0, d.getWidth(), d.getHeight()));
|
||||
extraSpaceArea.subtract(new Area(extraSpaceRect));
|
||||
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.05f));
|
||||
g2d.setTransform(extraSpaceTx);
|
||||
g2d.setColor(theme.getOutlineColor());
|
||||
g2d.fill(extraSpaceArea);
|
||||
}
|
||||
|
||||
return failedComponents;
|
||||
}
|
||||
|
||||
@@ -407,16 +454,26 @@ public class DrawingManager {
|
||||
return components;
|
||||
}
|
||||
|
||||
public Dimension getCanvasDimensions(Project project, Double zoomLevel, boolean useZoom) {
|
||||
public double getExtraSpace(Project project) {
|
||||
double width = project.getWidth().convertToPixels();
|
||||
double height = project.getHeight().convertToPixels();
|
||||
if (useZoom) {
|
||||
double targetExtraSpace = EXTRA_SPACE * Math.max(width, height);
|
||||
return CalcUtils.roundToGrid(targetExtraSpace, project.getGridSpacing());
|
||||
}
|
||||
|
||||
public Dimension getCanvasDimensions(Project project, Double zoomLevel, boolean includeExtraSpace) {
|
||||
double width = project.getWidth().convertToPixels();
|
||||
double height = project.getHeight().convertToPixels();
|
||||
|
||||
if (includeExtraSpace) {
|
||||
double extraSpace = getExtraSpace(project);
|
||||
width += 2 * extraSpace;
|
||||
height += 2 * extraSpace;
|
||||
}
|
||||
|
||||
width *= zoomLevel;
|
||||
height *= zoomLevel;
|
||||
} else {
|
||||
width /= Constants.PIXEL_SIZE;
|
||||
height /= Constants.PIXEL_SIZE;
|
||||
}
|
||||
|
||||
return new Dimension((int) width, (int) height);
|
||||
}
|
||||
|
||||
@@ -435,19 +492,32 @@ public class DrawingManager {
|
||||
messageDispatcher.dispatchMessage(EventType.REPAINT);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void findContinuityAreaAtPoint(Project project, Point p) {
|
||||
List<Area> areas = getContinuityAreas(project);
|
||||
|
||||
for (Area a : areas) {
|
||||
if (a.contains(p)) {
|
||||
continuityArea = a;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
continuityArea = null;
|
||||
}
|
||||
|
||||
public List<Area> getContinuityAreas(Project project) {
|
||||
// Find all individual continuity areas for all components
|
||||
List<Area> preliminaryAreas = new ArrayList<Area>();
|
||||
List<Boolean> checkBreakout = new ArrayList<Boolean>();
|
||||
List<Connection> connections = new ArrayList<Connection>();
|
||||
Set<Connection> connections = new HashSet<Connection>();
|
||||
for (IDIYComponent<?> c : project.getComponents()) {
|
||||
ComponentArea a = getComponentArea(c);
|
||||
|
||||
ComponentType type =
|
||||
ComponentProcessor.getInstance().extractComponentTypeFrom((Class<? extends IDIYComponent<?>>) c.getClass());
|
||||
if (type.isContinuity()) {
|
||||
connections.add(new Connection(c.getControlPoint(0), c.getControlPoint(c.getControlPointCount() - 1)));
|
||||
if (c instanceof IContinuity) {
|
||||
for (int i = 0; i < c.getControlPointCount() - 1; i++)
|
||||
for (int j = i + 1; j < c.getControlPointCount(); j++)
|
||||
if (((IContinuity)c).arePointsConnected(i, j))
|
||||
connections.add(new Connection(c.getControlPoint(i), c.getControlPoint(j)));
|
||||
}
|
||||
|
||||
if (a == null || a.getOutlineArea() == null)
|
||||
@@ -479,19 +549,40 @@ public class DrawingManager {
|
||||
// areas.add(a);
|
||||
}
|
||||
|
||||
expandConnections(connections);
|
||||
|
||||
crunchAreas(areas, connections);
|
||||
|
||||
for (Area a : areas) {
|
||||
if (a.contains(p)) {
|
||||
continuityArea = a;
|
||||
return;
|
||||
}
|
||||
return areas;
|
||||
}
|
||||
|
||||
continuityArea = null;
|
||||
public void expandConnections(Set<Connection> connections) {
|
||||
Set<Connection> toAdd = new HashSet<Connection>();
|
||||
for (Connection c1 : connections)
|
||||
for (Connection c2 : connections) {
|
||||
if (c1 == c2)
|
||||
continue;
|
||||
if (c1.getP1().distance(c2.getP1()) < CONTROL_POINT_SIZE)
|
||||
toAdd.add(new Connection(c1.getP2(), c2.getP2()));
|
||||
if (c1.getP1().distance(c2.getP2()) < CONTROL_POINT_SIZE)
|
||||
toAdd.add(new Connection(c1.getP2(), c2.getP1()));
|
||||
if (c1.getP2().distance(c2.getP1()) < CONTROL_POINT_SIZE)
|
||||
toAdd.add(new Connection(c1.getP1(), c2.getP2()));
|
||||
if (c1.getP2().distance(c2.getP2()) < CONTROL_POINT_SIZE)
|
||||
toAdd.add(new Connection(c1.getP1(), c2.getP1()));
|
||||
}
|
||||
if (connections.addAll(toAdd))
|
||||
expandConnections(connections);
|
||||
}
|
||||
|
||||
private boolean crunchAreas(List<Area> areas, List<Connection> connections) {
|
||||
/**
|
||||
* Merges all areas that either overlap or are joined by connections.
|
||||
*
|
||||
* @param areas
|
||||
* @param connections
|
||||
* @return
|
||||
*/
|
||||
private boolean crunchAreas(List<Area> areas, Set<Connection> connections) {
|
||||
boolean isChanged = false;
|
||||
|
||||
List<Area> newAreas = new ArrayList<Area>();
|
||||
@@ -505,15 +596,19 @@ public class DrawingManager {
|
||||
continue;
|
||||
Area a1 = areas.get(i);
|
||||
Area a2 = areas.get(j);
|
||||
Area intersection = new Area(a1);
|
||||
Area intersection = null;
|
||||
if (a1.getBounds2D().intersects(a2.getBounds())) {
|
||||
intersection = new Area(a1);
|
||||
intersection.intersect(a2);
|
||||
}
|
||||
// if the two areas intersect, make a union and consume the second area
|
||||
if (!intersection.isEmpty()) {
|
||||
if (intersection != null && !intersection.isEmpty()) {
|
||||
a1.add(a2);
|
||||
consumed.set(j, true);
|
||||
} else { // maybe there's a connection between them
|
||||
for (Connection p : connections) {
|
||||
if ((a1.contains(p.pointA) && a2.contains(p.pointB)) || (a1.contains(p.pointB) && a2.contains(p.pointA))) {
|
||||
for (Connection p : connections) { // use getBounds to optimize the computation, don't get into complex math if not needed
|
||||
if ((a1.getBounds().contains(p.getP1()) && a2.getBounds().contains(p.getP2()) && a1.contains(p.getP1()) && a2.contains(p.getP2())) ||
|
||||
(a1.getBounds().contains(p.getP2()) && a2.getBounds().contains(p.getP1())) && a1.contains(p.getP2()) && a2.contains(p.getP1())) {
|
||||
a1.add(a2);
|
||||
consumed.set(j, true);
|
||||
break;
|
||||
@@ -572,24 +667,4 @@ public class DrawingManager {
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
class Connection {
|
||||
|
||||
private Point pointA;
|
||||
private Point pointB;
|
||||
|
||||
public Connection(Point pointA, Point pointB) {
|
||||
super();
|
||||
this.pointA = pointA;
|
||||
this.pointB = pointB;
|
||||
}
|
||||
|
||||
public Point getPointA() {
|
||||
return pointA;
|
||||
}
|
||||
|
||||
public Point getPointB() {
|
||||
return pointB;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2018 held jointly by the individual authors.
|
||||
|
||||
This file is part of DIYLC.
|
||||
|
||||
DIYLC is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DIYLC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package org.diylc.presenter;
|
||||
|
||||
import java.awt.Font;
|
||||
|
||||
import com.thoughtworks.xstream.converters.MarshallingContext;
|
||||
import com.thoughtworks.xstream.converters.UnmarshallingContext;
|
||||
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
|
||||
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
|
||||
|
||||
/**
|
||||
* Serializes {@link Font} objects in a more compact fashion. Backwards compatible when unmarshalling.
|
||||
*
|
||||
* @author Branislav Stojkovic
|
||||
*/
|
||||
public class FontConverter extends com.thoughtworks.xstream.converters.extended.FontConverter {
|
||||
|
||||
@Override
|
||||
public void marshal(Object object, HierarchicalStreamWriter writer, MarshallingContext context) {
|
||||
Font f = (Font) object;
|
||||
writer.addAttribute("name", f.getFontName());
|
||||
writer.addAttribute("size", Integer.toString(f.getSize()));
|
||||
writer.addAttribute("style", Integer.toString(f.getStyle()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
|
||||
if (reader.getAttribute("name") != null) {
|
||||
return new Font(reader.getAttribute("name"), Integer.parseInt(reader.getAttribute("style")), Integer.parseInt(reader.getAttribute("size")));
|
||||
}
|
||||
return super.unmarshal(reader, context);
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public boolean canConvert(Class clazz) {
|
||||
return Font.class.isAssignableFrom(clazz);
|
||||
}
|
||||
}
|
||||
@@ -55,6 +55,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.diylc.common.ObjectCache;
|
||||
import org.diylc.common.ZoomableStroke;
|
||||
import org.diylc.core.IDrawingObserver;
|
||||
|
||||
/**
|
||||
@@ -161,6 +162,10 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
|
||||
this.trackingContinuityAllowed = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTrackingContinuityArea() {
|
||||
return trackingContinuityAllowed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends shape interior to the current component area.
|
||||
@@ -403,11 +408,11 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
|
||||
|
||||
@Override
|
||||
public void setStroke(Stroke s) {
|
||||
if (this.zoom > 1 && s.getClass() == BasicStroke.class) {
|
||||
if (this.zoom > 1 && s instanceof BasicStroke) {
|
||||
BasicStroke bs = (BasicStroke) s;
|
||||
// make thin lines even thinner to compensate for zoom factor
|
||||
if (bs.getLineWidth() <= 2)
|
||||
s = ObjectCache.getInstance().fetchBasicStroke((float) (bs.getLineWidth() / zoom));
|
||||
if (bs.getLineWidth() <= 2 && !(s instanceof ZoomableStroke))
|
||||
s = ObjectCache.getInstance().fetchStroke((float) (bs.getLineWidth() / zoom), bs.getDashArray(), bs.getDashPhase(), bs.getEndCap());
|
||||
}
|
||||
canvasGraphics.setStroke(s);
|
||||
}
|
||||
|
||||
@@ -27,8 +27,10 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.diylc.appframework.miscutils.ConfigurationManager;
|
||||
@@ -61,9 +63,12 @@ public class InstantiationManager {
|
||||
private Point firstControlPoint;
|
||||
private Point potentialControlPoint;
|
||||
|
||||
private static final ComponentType clipboardType = new ComponentType("Clipboard contents",
|
||||
"Components from the clipboard", CreationMethod.SINGLE_CLICK, "Multi", "", "", null, null, 0, false, false, null,
|
||||
false, null, KeywordPolicy.NEVER_SHOW, null, false);
|
||||
public static final ComponentType clipboardType = new ComponentType("Clipboard contents",
|
||||
"Components from the clipboard", CreationMethod.SINGLE_CLICK, "Multi", "", "", null, null, 0, false, null,
|
||||
false, null, KeywordPolicy.NEVER_SHOW, null);
|
||||
public static final ComponentType blockType = new ComponentType("Building block",
|
||||
"Components from the building block", CreationMethod.SINGLE_CLICK, "Multi", "", "", null, null, 0, false, null,
|
||||
false, null, KeywordPolicy.NEVER_SHOW, null);
|
||||
|
||||
public InstantiationManager() {}
|
||||
|
||||
@@ -87,7 +92,11 @@ public class InstantiationManager {
|
||||
return potentialControlPoint;
|
||||
}
|
||||
|
||||
public void setComponentTypeSlot(ComponentType componentTypeSlot, Template template, Project currentProject)
|
||||
public void setPotentialControlPoint(Point potentialControlPoint) {
|
||||
this.potentialControlPoint = potentialControlPoint;
|
||||
}
|
||||
|
||||
public void setComponentTypeSlot(ComponentType componentTypeSlot, Template template, Project currentProject, boolean forceInstatiate)
|
||||
throws Exception {
|
||||
this.componentTypeSlot = componentTypeSlot;
|
||||
this.template = template;
|
||||
@@ -96,7 +105,7 @@ public class InstantiationManager {
|
||||
} else {
|
||||
switch (componentTypeSlot.getCreationMethod()) {
|
||||
case POINT_BY_POINT:
|
||||
this.componentSlot = null;
|
||||
this.componentSlot = forceInstatiate ? instantiateComponent(componentTypeSlot, template, new Point(0, 0), currentProject) : null;
|
||||
break;
|
||||
case SINGLE_CLICK:
|
||||
this.componentSlot = instantiateComponent(componentTypeSlot, template, new Point(0, 0), currentProject);
|
||||
@@ -132,15 +141,33 @@ public class InstantiationManager {
|
||||
return changeMade;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void pasteComponents(Collection<IDIYComponent<?>> components, Point scaledPoint, boolean snapToGrid,
|
||||
Size gridSpacing) {
|
||||
Size gridSpacing, boolean autoGroup, Project currentProject) {
|
||||
// Adjust location of components so they are centered under the mouse
|
||||
// cursor
|
||||
int minX = Integer.MAX_VALUE;
|
||||
int maxX = Integer.MIN_VALUE;
|
||||
int minY = Integer.MAX_VALUE;
|
||||
int maxY = Integer.MIN_VALUE;
|
||||
|
||||
Set<String> existingNames = new HashSet<String>();
|
||||
for (IDIYComponent<?> c : currentProject.getComponents())
|
||||
existingNames.add(c.getName());
|
||||
|
||||
List<IDIYComponent<?>> allComponents = new ArrayList<IDIYComponent<?>>(currentProject.getComponents());
|
||||
|
||||
for (IDIYComponent<?> component : components) {
|
||||
// assign a new name if it already exists in the project
|
||||
if (existingNames.contains(component.getName())) {
|
||||
ComponentType componentType =
|
||||
ComponentProcessor.getInstance().extractComponentTypeFrom((Class<? extends IDIYComponent<?>>) component.getClass());
|
||||
String newName = createUniqueName(componentType, allComponents);
|
||||
existingNames.add(newName);
|
||||
component.setName(newName);
|
||||
allComponents.add(component);
|
||||
}
|
||||
|
||||
for (int i = 0; i < component.getControlPointCount(); i++) {
|
||||
Point p = component.getControlPoint(i);
|
||||
if (p.x > maxX) {
|
||||
@@ -176,7 +203,7 @@ public class InstantiationManager {
|
||||
|
||||
// Update the component type slot so the app knows that something's
|
||||
// being instantiated.
|
||||
this.componentTypeSlot = clipboardType;
|
||||
this.componentTypeSlot = autoGroup ? blockType : clipboardType;
|
||||
|
||||
if (snapToGrid) {
|
||||
scaledPoint = new Point(scaledPoint);
|
||||
@@ -229,7 +256,7 @@ public class InstantiationManager {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<IDIYComponent<?>> instantiateComponent(ComponentType componentType, Template template, Point point,
|
||||
Project currentProject) throws Exception {
|
||||
Project currentProject) throws InstantiationException, IllegalAccessException {
|
||||
LOG.info("Instatiating component of type: " + componentType.getInstanceClass().getName());
|
||||
|
||||
// Instantiate the component.
|
||||
@@ -314,8 +341,7 @@ public class InstantiationManager {
|
||||
* @throws NoSuchMethodException
|
||||
* @throws SecurityException
|
||||
*/
|
||||
public void fillWithDefaultProperties(Object object, Template template) throws IllegalArgumentException,
|
||||
IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException {
|
||||
public void fillWithDefaultProperties(Object object, Template template) {
|
||||
// Extract properties.
|
||||
List<PropertyWrapper> properties = ComponentProcessor.getInstance().extractProperties(object.getClass());
|
||||
Map<String, PropertyWrapper> propertyCache = new HashMap<String, PropertyWrapper>();
|
||||
@@ -327,7 +353,11 @@ public class InstantiationManager {
|
||||
Presenter.DEFAULTS_KEY_PREFIX + object.getClass().getName() + ":" + property.getName(), null);
|
||||
if (defaultValue != null) {
|
||||
property.setValue(defaultValue);
|
||||
try {
|
||||
property.writeTo(object);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Could not write property " + property.getName(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (template != null) {
|
||||
@@ -338,7 +368,11 @@ public class InstantiationManager {
|
||||
} else {
|
||||
LOG.debug("Filling value from template for " + pair.getKey());
|
||||
property.setValue(pair.getValue());
|
||||
try {
|
||||
property.writeTo(object);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Could not write property " + property.getName(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -371,7 +405,8 @@ public class InstantiationManager {
|
||||
PropertyWrapper angleProperty = null;
|
||||
for (PropertyWrapper propertyWrapper : properties) {
|
||||
if (propertyWrapper.getType().getName().equals(Orientation.class.getName())
|
||||
|| propertyWrapper.getType().getName().equals(OrientationHV.class.getName())) {
|
||||
|| propertyWrapper.getType().getName().equals(OrientationHV.class.getName())
|
||||
|| propertyWrapper.getName().equalsIgnoreCase("angle")) {
|
||||
angleProperty = propertyWrapper;
|
||||
break;
|
||||
}
|
||||
@@ -390,6 +425,12 @@ public class InstantiationManager {
|
||||
} else if (value instanceof OrientationHV) {
|
||||
angleProperty.setValue(OrientationHV.values()[(((OrientationHV) value).ordinal() + 1)
|
||||
% OrientationHV.values().length]);
|
||||
} else if (angleProperty.getName().equalsIgnoreCase("angle")) {
|
||||
int angle = (Integer) angleProperty.getValue();
|
||||
angle += 90;
|
||||
if (angle >= 360)
|
||||
angle -= 360;
|
||||
angleProperty.setValue(angle);
|
||||
}
|
||||
angleProperty.writeTo(component);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2018 held jointly by the individual authors.
|
||||
|
||||
This file is part of DIYLC.
|
||||
|
||||
DIYLC is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DIYLC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package org.diylc.presenter;
|
||||
|
||||
import org.diylc.core.measures.AbstractMeasure;
|
||||
|
||||
import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;
|
||||
|
||||
import com.thoughtworks.xstream.converters.Converter;
|
||||
import com.thoughtworks.xstream.converters.MarshallingContext;
|
||||
import com.thoughtworks.xstream.converters.UnmarshallingContext;
|
||||
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
|
||||
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
|
||||
|
||||
/**
|
||||
* Serializes objects of types derived from {@link AbstractMeasure} objects in a compact format. Backwards compatible when unmarshalling.
|
||||
*
|
||||
* @author Branislav Stojkovic
|
||||
*/
|
||||
public class MeasureConverter implements Converter {
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public void marshal(Object object, HierarchicalStreamWriter writer, MarshallingContext context) {
|
||||
AbstractMeasure m = (AbstractMeasure) object;
|
||||
if (m.getValue() != null)
|
||||
writer.addAttribute("value", Double.toString(m.getValue()));
|
||||
if (m.getUnit() != null)
|
||||
writer.addAttribute("unit", m.getUnit().name());
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
@Override
|
||||
public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
|
||||
Double value = null;
|
||||
String unitStr = null;
|
||||
if (reader.getAttribute("value") != null) {
|
||||
value = Double.parseDouble(reader.getAttribute("value"));
|
||||
unitStr = reader.getAttribute("unit");
|
||||
} else {
|
||||
if (reader.hasMoreChildren()) {
|
||||
reader.moveDown();
|
||||
if (reader.getNodeName().equals("value"))
|
||||
value = Double.parseDouble(reader.getValue());
|
||||
else if (reader.getNodeName().equals("unit"))
|
||||
unitStr = reader.getValue();
|
||||
reader.moveUp();
|
||||
}
|
||||
if (reader.hasMoreChildren()) {
|
||||
reader.moveDown();
|
||||
if (reader.getNodeName().equals("value"))
|
||||
value = Double.parseDouble(reader.getValue());
|
||||
else if (reader.getNodeName().equals("unit"))
|
||||
unitStr = reader.getValue();
|
||||
reader.moveUp();
|
||||
}
|
||||
}
|
||||
try {
|
||||
Class requiredType = context.getRequiredType();
|
||||
ParameterizedTypeImpl generic = (ParameterizedTypeImpl)requiredType.getGenericSuperclass();
|
||||
Class unitType = (Class)generic.getActualTypeArguments()[0];
|
||||
Object unit = unitStr == null ? null : Enum.valueOf(unitType, unitStr);
|
||||
return requiredType.getConstructor(Double.class, unitType).newInstance(value, unit);
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public boolean canConvert(Class clazz) {
|
||||
return AbstractMeasure.class.isAssignableFrom(clazz);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -21,6 +21,7 @@
|
||||
*/
|
||||
package org.diylc.presenter;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
@@ -32,6 +33,7 @@ import java.io.Writer;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -42,15 +44,19 @@ import javax.xml.parsers.ParserConfigurationException;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.diylc.appframework.miscutils.Utils;
|
||||
import org.diylc.appframework.simplemq.MessageDispatcher;
|
||||
import org.diylc.appframework.update.VersionNumber;
|
||||
import org.diylc.common.EventType;
|
||||
import org.diylc.core.Project;
|
||||
import org.diylc.parsing.IOldFileParser;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import com.thoughtworks.xstream.XStream;
|
||||
import com.thoughtworks.xstream.io.xml.DomDriver;
|
||||
import com.thoughtworks.xstream.mapper.MapperWrapper;
|
||||
|
||||
public class ProjectFileManager {
|
||||
|
||||
@@ -68,11 +74,45 @@ public class ProjectFileManager {
|
||||
|
||||
private List<IOldFileParser> parsers;
|
||||
|
||||
private Set<String> missingFields = new HashSet<String>();
|
||||
|
||||
public ProjectFileManager(MessageDispatcher<EventType> messageDispatcher) {
|
||||
super();
|
||||
this.xStream = new XStream(new DomDriver("UTF-8"));
|
||||
this.xStream = new XStream(new DomDriver("UTF-8")) {
|
||||
|
||||
@Override
|
||||
protected MapperWrapper wrapMapper(MapperWrapper next) {
|
||||
return new MapperWrapper(next) {
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public boolean shouldSerializeMember(Class definedIn, String fieldName) {
|
||||
if (definedIn == Object.class) {
|
||||
missingFields.add(definedIn.getName() + "." + fieldName);
|
||||
return false;
|
||||
}
|
||||
return super.shouldSerializeMember(definedIn, fieldName);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
xStream.autodetectAnnotations(true);
|
||||
xStream.alias("point", java.awt.Point.class);
|
||||
xStream.alias("font", java.awt.Font.class);
|
||||
xStream.alias("project", Project.class);
|
||||
xStream.aliasPackage("diylc", "org.diylc.components");
|
||||
xStream.registerConverter(new PointConverter());
|
||||
xStream.registerConverter(new ColorConverter());
|
||||
xStream.registerConverter(new FontConverter());
|
||||
xStream.registerConverter(new MeasureConverter());
|
||||
xStream.addImmutableType(Color.class);
|
||||
xStream.addImmutableType(java.awt.Point.class);
|
||||
xStream.addImmutableType(org.diylc.core.measures.Voltage.class);
|
||||
xStream.addImmutableType(org.diylc.core.measures.Resistance.class);
|
||||
xStream.addImmutableType(org.diylc.core.measures.Capacitance.class);
|
||||
xStream.addImmutableType(org.diylc.core.measures.Current.class);
|
||||
xStream.addImmutableType(org.diylc.core.measures.Power.class);
|
||||
xStream.addImmutableType(org.diylc.core.measures.Inductance.class);
|
||||
xStream.addImmutableType(org.diylc.core.measures.Size.class);
|
||||
this.xStreamOld = new XStream(new DomDriver());
|
||||
xStreamOld.autodetectAnnotations(true);
|
||||
this.messageDispatcher = messageDispatcher;
|
||||
@@ -130,8 +170,8 @@ public class ProjectFileManager {
|
||||
DocumentBuilder db = dbf.newDocumentBuilder();
|
||||
Document doc = db.parse(new InputSource(new InputStreamReader(new FileInputStream(file))));
|
||||
doc.getDocumentElement().normalize();
|
||||
if (doc.getDocumentElement().getNodeName().equalsIgnoreCase(Project.class.getName())) {
|
||||
project = parseV3File(fileName);
|
||||
if (doc.getDocumentElement().getNodeName().equals(Project.class.getName()) || doc.getDocumentElement().getNodeName().equals("project")) {
|
||||
project = parseV3File(fileName, warnings);
|
||||
} else {
|
||||
if (!doc.getDocumentElement().getNodeName().equalsIgnoreCase("layout")) {
|
||||
throw new IllegalArgumentException("Could not open DIY file. Root node is not named 'Layout'.");
|
||||
@@ -171,19 +211,58 @@ public class ProjectFileManager {
|
||||
messageDispatcher.dispatchMessage(EventType.FILE_STATUS_CHANGED, getCurrentFileName(), isModified());
|
||||
}
|
||||
|
||||
private Project parseV3File(String fileName) throws IOException {
|
||||
private Project parseV3File(String fileName, List<String> warnings) throws IOException {
|
||||
Project project;
|
||||
VersionNumber fileVersion;
|
||||
try {
|
||||
fileVersion = readV3Version(fileName);
|
||||
if (fileVersion.compareTo(Presenter.CURRENT_VERSION) > 0)
|
||||
warnings.add("The file is created with a newer version of DIYLC and may contain features that are not supported by your version of DIYLC. Please update.");
|
||||
} catch (Exception e) {
|
||||
warnings.add("Could not read file version number, the file may be corrupted.");
|
||||
}
|
||||
FileInputStream fis = new FileInputStream(fileName);
|
||||
missingFields.clear();
|
||||
try {
|
||||
Reader reader = new InputStreamReader(fis, "UTF-8");
|
||||
project = (Project) xStream.fromXML(reader);
|
||||
} catch (Exception e) {
|
||||
LOG.warn("Could not open with the new xStream, trying the old one");
|
||||
LOG.warn("Could not open with the new xStream, trying the old one", e);
|
||||
fis.close();
|
||||
fis = new FileInputStream(fileName);
|
||||
project = (Project) xStreamOld.fromXML(fis);
|
||||
}
|
||||
if (!missingFields.isEmpty()) {
|
||||
warnings.add("The project references unknown component properties, most likely because it was created with a newer version of DIYLC.");
|
||||
}
|
||||
fis.close();
|
||||
return project;
|
||||
}
|
||||
|
||||
private VersionNumber readV3Version(String fileName) throws Exception {
|
||||
File fXmlFile = new File(fileName);
|
||||
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
|
||||
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
|
||||
Document doc = dBuilder.parse(fXmlFile);
|
||||
|
||||
doc.getDocumentElement().normalize();
|
||||
|
||||
NodeList nList = doc.getElementsByTagName("fileVersion");
|
||||
|
||||
int items = nList.getLength();
|
||||
|
||||
if (items != 1)
|
||||
throw new Exception("File version information could not be read from the XML.");
|
||||
|
||||
Node versionNode = nList.item(0);
|
||||
Node n = versionNode.getFirstChild().getNextSibling();
|
||||
int major = Integer.parseInt(n.getFirstChild().getNodeValue());
|
||||
n = n.getNextSibling().getNextSibling();
|
||||
int minor = Integer.parseInt(n.getFirstChild().getNodeValue());
|
||||
n = n.getNextSibling().getNextSibling();
|
||||
int build = Integer.parseInt(n.getFirstChild().getNodeValue());
|
||||
|
||||
return new VersionNumber(major, minor, build);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ public class Constants {
|
||||
public static Color CANVAS_COLOR = Color.white;
|
||||
|
||||
public static final Stroke DASHED_STROKE = new BasicStroke(1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10f,
|
||||
new float[] {2.0f}, 0.0f);
|
||||
new float[] {2.0f, 4.0f}, 0.0f);
|
||||
|
||||
public static final Theme DEFAULT_THEME = new Theme("Light", Constants.CANVAS_COLOR, new Color(240, 240, 240),
|
||||
Color.black);
|
||||
|
||||
@@ -25,6 +25,8 @@ import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import org.diylc.core.IDIYComponent;
|
||||
@@ -48,11 +50,17 @@ public class BomMakerTest {
|
||||
List<BomEntry> bom = BomMaker.getInstance().createBom(components);
|
||||
assertNotNull(bom);
|
||||
assertEquals(2, bom.size());
|
||||
Collections.sort(bom, new Comparator<BomEntry>() {
|
||||
|
||||
@Override
|
||||
public int compare(BomEntry o1, BomEntry o2) {
|
||||
return o1.getQuantity().compareTo(o2.getQuantity());
|
||||
}});
|
||||
BomEntry entry1 = bom.get(0);
|
||||
assertEquals("something", entry1.getName());
|
||||
assertEquals(2, (int) entry1.getQuantity());
|
||||
assertEquals(1, (int) entry1.getQuantity());
|
||||
BomEntry entry2 = bom.get(1);
|
||||
assertEquals("something", entry2.getName());
|
||||
assertEquals(1, (int) entry2.getQuantity());
|
||||
assertEquals("something, something", entry2.getName());
|
||||
assertEquals(2, (int) entry2.getQuantity());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,4 +164,9 @@ public class MockDIYComponent extends AbstractComponent<Capacitance> {
|
||||
public void drawIcon(Graphics2D g2d, int width, int height) {
|
||||
g2d.drawString("X", 10, 10);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getControlPointNodeName(int index) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="src" path="test"/>
|
||||
<classpathentry kind="lib" path="lib/log4j-1.2.15.jar"/>
|
||||
<classpathentry kind="lib" path="lib/app-framework.jar"/>
|
||||
<classpathentry kind="lib" path="lib/jep-2.4.1.jar"/>
|
||||
<classpathentry kind="lib" path="lib/poi-3.5-FINAL-20090928.jar"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/diylc-core"/>
|
||||
<classpathentry kind="lib" path="lib/xstream-1.4.3.jar"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/jdk1.6.0_45"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2018 held jointly by the individual authors.
|
||||
|
||||
This file is part of DIYLC.
|
||||
|
||||
DIYLC is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DIYLC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package org.diylc.awt;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Paint;
|
||||
import java.awt.PaintContext;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.ColorModel;
|
||||
|
||||
public class ShadedPaint implements Paint {
|
||||
|
||||
private ShadedPaintContext context;
|
||||
private Point2D p1;
|
||||
private Point2D p2;
|
||||
private Color c1;
|
||||
private Color c2;
|
||||
|
||||
public ShadedPaint(Point2D p1, Point2D p2, Color c, double shadeFactor) {
|
||||
this.p1 = p1;
|
||||
this.p2 = p2;
|
||||
int r = c.getRed();
|
||||
int g = c.getGreen();
|
||||
int b = c.getBlue();
|
||||
|
||||
this.c1 = new Color(
|
||||
Math.max((int) (r * shadeFactor), 0),
|
||||
Math.max((int) (g * shadeFactor), 0),
|
||||
Math.max((int) (b * shadeFactor), 0));
|
||||
|
||||
|
||||
int i = (int)(1.0/(1.0-shadeFactor));
|
||||
if ( r == 0 && g == 0 && b == 0) {
|
||||
this.c2 = new Color(i, i, i);
|
||||
} else {
|
||||
if ( r > 0 && r < i ) r = i;
|
||||
if ( g > 0 && g < i ) g = i;
|
||||
if ( b > 0 && b < i ) b = i;
|
||||
|
||||
this.c2 = new Color(Math.min((int)(r / shadeFactor), 255),
|
||||
Math.min((int)(g / shadeFactor), 255),
|
||||
Math.min((int)(b / shadeFactor), 255));
|
||||
}
|
||||
}
|
||||
|
||||
public ShadedPaint(Point2D p1, Point2D p2, Color c2) {
|
||||
this(p1, p2, c2, 0.9f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTransparency() {
|
||||
return OPAQUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaintContext createContext(ColorModel cm, Rectangle deviceBounds, Rectangle2D userBounds,
|
||||
AffineTransform xform, RenderingHints hints) {
|
||||
if (context == null || !context.getColorModel().equals(cm))
|
||||
context = new ShadedPaintContext(cm, p1, p2, xform, c1, c2);
|
||||
return context;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2018 held jointly by the individual authors.
|
||||
|
||||
This file is part of DIYLC.
|
||||
|
||||
DIYLC is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DIYLC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package org.diylc.awt;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.PaintContext;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.NoninvertibleTransformException;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.DirectColorModel;
|
||||
import java.awt.image.Raster;
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import sun.awt.image.IntegerComponentRaster;
|
||||
|
||||
public class ShadedPaintContext implements PaintContext {
|
||||
|
||||
static ColorModel xrgbmodel =
|
||||
new DirectColorModel(24, 0x00ff0000, 0x0000ff00, 0x000000ff);
|
||||
static ColorModel xbgrmodel =
|
||||
new DirectColorModel(24, 0x000000ff, 0x0000ff00, 0x00ff0000);
|
||||
|
||||
static ColorModel cachedModel;
|
||||
static WeakReference<Raster> cached;
|
||||
|
||||
static synchronized Raster getCachedRaster(ColorModel cm, int w, int h) {
|
||||
if (cm == cachedModel) {
|
||||
if (cached != null) {
|
||||
Raster ras = (Raster) cached.get();
|
||||
if (ras != null &&
|
||||
ras.getWidth() >= w &&
|
||||
ras.getHeight() >= h)
|
||||
{
|
||||
cached = null;
|
||||
return ras;
|
||||
}
|
||||
}
|
||||
}
|
||||
return cm.createCompatibleWritableRaster(w, h);
|
||||
}
|
||||
|
||||
static synchronized void putCachedRaster(ColorModel cm, Raster ras) {
|
||||
if (cached != null) {
|
||||
Raster cras = (Raster) cached.get();
|
||||
if (cras != null) {
|
||||
int cw = cras.getWidth();
|
||||
int ch = cras.getHeight();
|
||||
int iw = ras.getWidth();
|
||||
int ih = ras.getHeight();
|
||||
if (cw >= iw && ch >= ih) {
|
||||
return;
|
||||
}
|
||||
if (cw * ch >= iw * ih) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
cachedModel = cm;
|
||||
cached = new WeakReference<Raster>(ras);
|
||||
}
|
||||
|
||||
double x1;
|
||||
double y1;
|
||||
double dx;
|
||||
double dy;
|
||||
int interp[];
|
||||
Raster saved;
|
||||
ColorModel model;
|
||||
|
||||
public ShadedPaintContext(ColorModel cm,
|
||||
Point2D p1, Point2D p2, AffineTransform xform,
|
||||
Color c1, Color c2) {
|
||||
// First calculate the distance moved in user space when
|
||||
// we move a single unit along the X & Y axes in device space.
|
||||
Point2D xvec = new Point2D.Double(1, 0);
|
||||
Point2D yvec = new Point2D.Double(0, 1);
|
||||
try {
|
||||
AffineTransform inverse = xform.createInverse();
|
||||
inverse.deltaTransform(xvec, xvec);
|
||||
inverse.deltaTransform(yvec, yvec);
|
||||
} catch (NoninvertibleTransformException e) {
|
||||
xvec.setLocation(0, 0);
|
||||
yvec.setLocation(0, 0);
|
||||
}
|
||||
|
||||
// Now calculate the (square of the) user space distance
|
||||
// between the anchor points. This value equals:
|
||||
// (UserVec . UserVec)
|
||||
double udx = p2.getX() - p1.getX();
|
||||
double udy = p2.getY() - p1.getY();
|
||||
double ulenSq = udx * udx + udy * udy;
|
||||
|
||||
if (ulenSq <= Double.MIN_VALUE) {
|
||||
dx = 0;
|
||||
dy = 0;
|
||||
} else {
|
||||
// Now calculate the proportional distance moved along the
|
||||
// vector from p1 to p2 when we move a unit along X & Y in
|
||||
// device space.
|
||||
//
|
||||
// The length of the projection of the Device Axis Vector is
|
||||
// its dot product with the Unit User Vector:
|
||||
// (DevAxisVec . (UserVec / Len(UserVec))
|
||||
//
|
||||
// The "proportional" length is that length divided again
|
||||
// by the length of the User Vector:
|
||||
// (DevAxisVec . (UserVec / Len(UserVec))) / Len(UserVec)
|
||||
// which simplifies to:
|
||||
// ((DevAxisVec . UserVec) / Len(UserVec)) / Len(UserVec)
|
||||
// which simplifies to:
|
||||
// (DevAxisVec . UserVec) / LenSquared(UserVec)
|
||||
dx = (xvec.getX() * udx + xvec.getY() * udy) / ulenSq;
|
||||
dy = (yvec.getX() * udx + yvec.getY() * udy) / ulenSq;
|
||||
|
||||
|
||||
// We are acyclic
|
||||
if (dx < 0) {
|
||||
// If we are using the acyclic form below, we need
|
||||
// dx to be non-negative for simplicity of scanning
|
||||
// across the scan lines for the transition points.
|
||||
// To ensure that constraint, we negate the dx/dy
|
||||
// values and swap the points and colors.
|
||||
Point2D p = p1; p1 = p2; p2 = p;
|
||||
Color c = c1; c1 = c2; c2 = c;
|
||||
dx = -dx;
|
||||
dy = -dy;
|
||||
}
|
||||
}
|
||||
|
||||
Point2D dp1 = xform.transform(p1, null);
|
||||
this.x1 = dp1.getX();
|
||||
this.y1 = dp1.getY();
|
||||
|
||||
int rgb1 = c1.getRGB();
|
||||
int rgb2 = c2.getRGB();
|
||||
int a1 = (rgb1 >> 24) & 0xff;
|
||||
int r1 = (rgb1 >> 16) & 0xff;
|
||||
int g1 = (rgb1 >> 8) & 0xff;
|
||||
int b1 = (rgb1 ) & 0xff;
|
||||
int da = ((rgb2 >> 24) & 0xff) - a1;
|
||||
int dr = ((rgb2 >> 16) & 0xff) - r1;
|
||||
int dg = ((rgb2 >> 8) & 0xff) - g1;
|
||||
int db = ((rgb2 ) & 0xff) - b1;
|
||||
if (a1 == 0xff && da == 0) {
|
||||
model = xrgbmodel;
|
||||
if (cm instanceof DirectColorModel) {
|
||||
DirectColorModel dcm = (DirectColorModel) cm;
|
||||
int tmp = dcm.getAlphaMask();
|
||||
if ((tmp == 0 || tmp == 0xff) &&
|
||||
dcm.getRedMask() == 0xff &&
|
||||
dcm.getGreenMask() == 0xff00 &&
|
||||
dcm.getBlueMask() == 0xff0000)
|
||||
{
|
||||
model = xbgrmodel;
|
||||
tmp = r1; r1 = b1; b1 = tmp;
|
||||
tmp = dr; dr = db; db = tmp;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
model = ColorModel.getRGBdefault();
|
||||
}
|
||||
interp = new int[257];
|
||||
for (int i = 0; i <= 256; i++) {
|
||||
float rel = i / 256.0f;
|
||||
int rgb =
|
||||
(((int) (a1 + da * rel)) << 24) |
|
||||
(((int) (r1 + dr * rel)) << 16) |
|
||||
(((int) (g1 + dg * rel)) << 8) |
|
||||
(((int) (b1 + db * rel)) );
|
||||
interp[i] = rgb;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Release the resources allocated for the operation.
|
||||
*/
|
||||
public void dispose() {
|
||||
if (saved != null) {
|
||||
putCachedRaster(model, saved);
|
||||
saved = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ColorModel of the output.
|
||||
*/
|
||||
public ColorModel getColorModel() {
|
||||
return model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a Raster containing the colors generated for the graphics
|
||||
* operation.
|
||||
* @param x,y,w,h The area in device space for which colors are
|
||||
* generated.
|
||||
*/
|
||||
public Raster getRaster(int x, int y, int w, int h) {
|
||||
double rowrel = (x - x1) * dx + (y - y1) * dy;
|
||||
|
||||
Raster rast = saved;
|
||||
if (rast == null || rast.getWidth() < w || rast.getHeight() < h) {
|
||||
rast = getCachedRaster(model, w, h);
|
||||
saved = rast;
|
||||
}
|
||||
IntegerComponentRaster irast = (IntegerComponentRaster) rast;
|
||||
int off = irast.getDataOffset(0);
|
||||
int adjust = irast.getScanlineStride() - w;
|
||||
int[] pixels = irast.getDataStorage();
|
||||
|
||||
clipFillRaster(pixels, off, adjust, w, h, rowrel, dx, dy);
|
||||
|
||||
// irast.markDirty();
|
||||
|
||||
return rast;
|
||||
}
|
||||
|
||||
void clipFillRaster(int[] pixels, int off, int adjust, int w, int h,
|
||||
double rowrel, double dx, double dy) {
|
||||
while (--h >= 0) {
|
||||
double colrel = rowrel;
|
||||
int j = w;
|
||||
if (colrel <= 0.0) {
|
||||
int rgb = interp[0];
|
||||
do {
|
||||
pixels[off++] = rgb;
|
||||
colrel += dx;
|
||||
} while (--j > 0 && colrel <= 0.0);
|
||||
}
|
||||
while (colrel < 1.0 && --j >= 0) {
|
||||
pixels[off++] = interp[(int) (colrel < 0.5 ? colrel * 2 * 256 : (2 - colrel * 2) * 256)];
|
||||
colrel += dx;
|
||||
}
|
||||
if (j > 0) {
|
||||
int rgb = interp[256];
|
||||
do {
|
||||
pixels[off++] = rgb;
|
||||
} while (--j > 0);
|
||||
}
|
||||
|
||||
off += adjust;
|
||||
rowrel += dy;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2018 held jointly by the individual authors.
|
||||
|
||||
This file is part of DIYLC.
|
||||
|
||||
DIYLC is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DIYLC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package org.diylc.awt;
|
||||
|
||||
import java.awt.Font;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.font.FontRenderContext;
|
||||
import java.awt.font.GlyphVector;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.diylc.common.HorizontalAlignment;
|
||||
import org.diylc.common.VerticalAlignment;
|
||||
|
||||
/**
|
||||
* Globally available utility classes, mostly for string manipulation.
|
||||
*
|
||||
* @author Jim Menard, <a href="mailto:jimm@io.com">jimm@io.com</a>
|
||||
*/
|
||||
public class StringUtils {
|
||||
|
||||
public static void drawWrappedText(String text, Graphics2D g2d, int x, int y, int maxWidth, HorizontalAlignment horizontalAlignment) {
|
||||
FontMetrics textMetrics = g2d.getFontMetrics();
|
||||
List<String> lines = wrap(text, textMetrics, maxWidth);
|
||||
int lineHeight = textMetrics.getHeight();
|
||||
|
||||
if (horizontalAlignment == HorizontalAlignment.CENTER)
|
||||
x += maxWidth / 2;
|
||||
else if (horizontalAlignment == HorizontalAlignment.RIGHT)
|
||||
x += maxWidth;
|
||||
|
||||
for (String line : lines) {
|
||||
drawCenteredText(g2d, line, x, y, horizontalAlignment, VerticalAlignment.BOTTOM);
|
||||
y += lineHeight;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of strings, one for each line in the string after it has been wrapped to fit
|
||||
* lines of <var>maxWidth</var>. Lines end with any of cr, lf, or cr lf. A line ending at the end
|
||||
* of the string will not output a further, empty string.
|
||||
* <p>
|
||||
* This code assumes <var>str</var> is not <code>null</code>.
|
||||
*
|
||||
* @param str the string to split
|
||||
* @param fm needed for string width calculations
|
||||
* @param maxWidth the max line width, in points
|
||||
* @return a non-empty list of strings
|
||||
*/
|
||||
public static List<String> wrap(String str, FontMetrics fm, int maxWidth) {
|
||||
List<String> lines = splitIntoLines(str);
|
||||
if (lines.size() == 0)
|
||||
return lines;
|
||||
|
||||
ArrayList<String> strings = new ArrayList<String>();
|
||||
for (Iterator<String> iter = lines.iterator(); iter.hasNext();)
|
||||
wrapLineInto((String) iter.next(), strings, fm, maxWidth);
|
||||
return strings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a line of text and font metrics information, wrap the line and add the new line(s) to
|
||||
* <var>list</var>.
|
||||
*
|
||||
* @param line a line of text
|
||||
* @param list an output list of strings
|
||||
* @param fm font metrics
|
||||
* @param maxWidth maximum width of the line(s)
|
||||
*/
|
||||
public static void wrapLineInto(String line, List<String> list, FontMetrics fm, int maxWidth) {
|
||||
int len = line.length();
|
||||
int width;
|
||||
while (len > 0 && (width = fm.stringWidth(line)) > maxWidth) {
|
||||
// Guess where to split the line. Look for the next space before
|
||||
// or after the guess.
|
||||
int guess = len * maxWidth / width;
|
||||
String before = line.substring(0, guess).trim();
|
||||
|
||||
width = fm.stringWidth(before);
|
||||
int pos;
|
||||
if (width > maxWidth) // Too long
|
||||
pos = findBreakBefore(line, guess);
|
||||
else { // Too short or possibly just right
|
||||
pos = findBreakAfter(line, guess);
|
||||
if (pos != -1) { // Make sure this doesn't make us too long
|
||||
before = line.substring(0, pos).trim();
|
||||
if (fm.stringWidth(before) > maxWidth)
|
||||
pos = findBreakBefore(line, guess);
|
||||
}
|
||||
}
|
||||
if (pos == -1)
|
||||
pos = guess; // Split in the middle of the word
|
||||
|
||||
list.add(line.substring(0, pos).trim());
|
||||
line = line.substring(pos).trim();
|
||||
len = line.length();
|
||||
}
|
||||
if (len > 0)
|
||||
list.add(line);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the first whitespace character or '-' in <var>line</var> that is at or
|
||||
* before <var>start</var>. Returns -1 if no such character is found.
|
||||
*
|
||||
* @param line a string
|
||||
* @param start where to star looking
|
||||
*/
|
||||
public static int findBreakBefore(String line, int start) {
|
||||
for (int i = start; i >= 0; --i) {
|
||||
char c = line.charAt(i);
|
||||
if (Character.isWhitespace(c) || c == '-')
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the first whitespace character or '-' in <var>line</var> that is at or
|
||||
* after <var>start</var>. Returns -1 if no such character is found.
|
||||
*
|
||||
* @param line a string
|
||||
* @param start where to star looking
|
||||
*/
|
||||
public static int findBreakAfter(String line, int start) {
|
||||
int len = line.length();
|
||||
for (int i = start; i < len; ++i) {
|
||||
char c = line.charAt(i);
|
||||
if (Character.isWhitespace(c) || c == '-')
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of strings, one for each line in the string. Lines end with any of cr, lf, or
|
||||
* cr lf. A line ending at the end of the string will not output a further, empty string.
|
||||
* <p>
|
||||
* This code assumes <var>str</var> is not <code>null</code>.
|
||||
*
|
||||
* @param str the string to split
|
||||
* @return a non-empty list of strings
|
||||
*/
|
||||
public static List<String> splitIntoLines(String str) {
|
||||
List<String> strings = new ArrayList<String>();
|
||||
|
||||
int len = str.length();
|
||||
if (len == 0) {
|
||||
strings.add("");
|
||||
return strings;
|
||||
}
|
||||
|
||||
int lineStart = 0;
|
||||
|
||||
for (int i = 0; i < len; ++i) {
|
||||
char c = str.charAt(i);
|
||||
if (c == '\r') {
|
||||
int newlineLength = 1;
|
||||
if ((i + 1) < len && str.charAt(i + 1) == '\n')
|
||||
newlineLength = 2;
|
||||
strings.add(str.substring(lineStart, i));
|
||||
lineStart = i + newlineLength;
|
||||
if (newlineLength == 2) // skip \n next time through loop
|
||||
++i;
|
||||
} else if (c == '\n') {
|
||||
strings.add(str.substring(lineStart, i));
|
||||
lineStart = i + 1;
|
||||
}
|
||||
}
|
||||
if (lineStart < len)
|
||||
strings.add(str.substring(lineStart));
|
||||
|
||||
return strings;
|
||||
}
|
||||
|
||||
public static void drawCenteredText(Graphics2D g2d, String text, int x, int y, HorizontalAlignment horizontalAlignment,
|
||||
VerticalAlignment verticalAlignment) {
|
||||
String[] parts = text.split("\n");
|
||||
if (parts.length > 1) {
|
||||
FontMetrics fontMetrics = g2d.getFontMetrics();
|
||||
Rectangle stringBounds = fontMetrics.getStringBounds(parts[0], g2d).getBounds();
|
||||
for (int i = 0; i < parts.length; i++)
|
||||
drawCenteredText(g2d, parts[i], x, (int)(y - stringBounds.height * (parts.length - 1) / 2d + i * stringBounds.height), horizontalAlignment, verticalAlignment);
|
||||
return;
|
||||
}
|
||||
|
||||
FontMetrics fontMetrics = g2d.getFontMetrics();
|
||||
Rectangle stringBounds = fontMetrics.getStringBounds(text, g2d).getBounds();
|
||||
|
||||
Font font = g2d.getFont();
|
||||
FontRenderContext renderContext = g2d.getFontRenderContext();
|
||||
GlyphVector glyphVector = font.createGlyphVector(renderContext, text);
|
||||
Rectangle visualBounds = glyphVector.getVisualBounds().getBounds();
|
||||
|
||||
int textX = 0;
|
||||
switch (horizontalAlignment) {
|
||||
case CENTER:
|
||||
textX = x - stringBounds.width / 2;
|
||||
break;
|
||||
case LEFT:
|
||||
textX = x;
|
||||
break;
|
||||
case RIGHT:
|
||||
textX = x - stringBounds.width;
|
||||
break;
|
||||
}
|
||||
|
||||
int textY = 0;
|
||||
switch (verticalAlignment) {
|
||||
case TOP:
|
||||
textY = y + stringBounds.height;
|
||||
break;
|
||||
case CENTER:
|
||||
textY = y - visualBounds.height / 2 - visualBounds.y;
|
||||
break;
|
||||
case BOTTOM:
|
||||
textY = y - visualBounds.y;
|
||||
break;
|
||||
}
|
||||
|
||||
g2d.drawString(text, textX, textY);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2018 held jointly by the individual authors.
|
||||
|
||||
This file is part of DIYLC.
|
||||
|
||||
DIYLC is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DIYLC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package org.diylc.awt;
|
||||
|
||||
import java.awt.geom.Area;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import java.awt.geom.Path2D;
|
||||
import java.awt.geom.Point2D;
|
||||
|
||||
/**
|
||||
* Creates an are covered by the two circles and the area between them bordered by the two external common tangents.
|
||||
*
|
||||
* @author Branislav Stojkovic
|
||||
*/
|
||||
public class TwoCircleTangent extends Area {
|
||||
|
||||
public TwoCircleTangent(Point2D p1, Point2D p2, double r1, double r2) {
|
||||
double d = p1.distance(p2);
|
||||
double h = Math.sqrt(d * d - (r1 - r2) * (r1 - r2));
|
||||
double y = Math.sqrt(h * h + r2 * r2);
|
||||
double theta1 = Math.acos((r1 * r1 + d * d - y * y) / (2 * r1 * d)) + Math.atan2(p2.getY() - p1.getY(), p2.getX() - p1.getX());
|
||||
double theta2 = -Math.acos((r1 * r1 + d * d - y * y) / (2 * r1 * d)) + Math.atan2(p2.getY() - p1.getY(), p2.getX() - p1.getX());
|
||||
|
||||
Area a = new Area(new Ellipse2D.Double(p1.getX() - r1, p1.getY() - r1, r1 * 2, r1 * 2));
|
||||
a.add(new Area(new Ellipse2D.Double(p2.getX() - r2, p2.getY() - r2, r2 * 2, r2 * 2)));
|
||||
Path2D path = new Path2D.Double();
|
||||
path.moveTo(p1.getX() + r1 * Math.cos(theta1), p1.getY() + r1 * Math.sin(theta1));
|
||||
path.lineTo(p2.getX() + r2 * Math.cos(theta1), p2.getY() + r2 * Math.sin(theta1));
|
||||
path.lineTo(p2.getX() + r2 * Math.cos(theta2), p2.getY() + r2 * Math.sin(theta2));
|
||||
path.lineTo(p1.getX() + r1 * Math.cos(theta2), p1.getY() + r1 * Math.sin(theta2));
|
||||
path.closePath();
|
||||
a.add(new Area(path));
|
||||
add(a);
|
||||
}
|
||||
}
|
||||
@@ -31,13 +31,13 @@ import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
import org.diylc.appframework.miscutils.ConfigurationManager;
|
||||
import org.diylc.awt.StringUtils;
|
||||
import org.diylc.common.Display;
|
||||
import org.diylc.common.HorizontalAlignment;
|
||||
import org.diylc.common.IPlugInPort;
|
||||
import org.diylc.common.ObjectCache;
|
||||
import org.diylc.common.Orientation;
|
||||
import org.diylc.common.VerticalAlignment;
|
||||
import org.diylc.components.AbstractComponent;
|
||||
import org.diylc.components.semiconductors.SymbolFlipping;
|
||||
import org.diylc.core.ComponentState;
|
||||
import org.diylc.core.IDrawingObserver;
|
||||
@@ -57,16 +57,31 @@ public abstract class Abstract3LegSymbol extends AbstractComponent<String> {
|
||||
public static Color COLOR = Color.black;
|
||||
|
||||
protected String value = "";
|
||||
protected Point[] controlPoints = new Point[] {new Point(0, 0), new Point(0, 0), new Point(0, 0)};
|
||||
protected Point[] controlPoints = new Point[] { new Point(0, 0), new Point(0, 0), new Point(0, 0), new Point(0, 0) };
|
||||
protected Color color = COLOR;
|
||||
protected SymbolFlipping flip = SymbolFlipping.NONE;
|
||||
protected Display display = Display.NAME;
|
||||
transient protected Shape[] body;
|
||||
protected Orientation orientation = Orientation.DEFAULT;
|
||||
protected boolean moveLabel = false;
|
||||
|
||||
public Abstract3LegSymbol() {
|
||||
super();
|
||||
updateControlPoints();
|
||||
controlPoints[3] = getDefaultLabelPosition(controlPoints);
|
||||
}
|
||||
|
||||
public Point[] getControlPoints() {
|
||||
if (controlPoints.length == 3) {
|
||||
controlPoints = new Point[] { controlPoints[0], controlPoints[1], controlPoints[2], getDefaultLabelPosition(controlPoints) };
|
||||
}
|
||||
return controlPoints;
|
||||
}
|
||||
|
||||
protected Point getDefaultLabelPosition(Point[] oldControlPoints) {
|
||||
int f = flip == SymbolFlipping.X ? -1 : 1;
|
||||
int d = flip == SymbolFlipping.X ? (int) PIN_SPACING.convertToPixels() / 2 : 0;
|
||||
return new Point(oldControlPoints[0].x + f * (int) (PIN_SPACING.convertToPixels() * 1.5 + d), oldControlPoints[0].y);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -88,12 +103,15 @@ public abstract class Abstract3LegSymbol extends AbstractComponent<String> {
|
||||
}
|
||||
g2d.setColor(finalColor);
|
||||
|
||||
// Draw transistor
|
||||
|
||||
Shape[] body = getBody();
|
||||
if (this.body == null) {
|
||||
this.body = getBody();
|
||||
applyOrientation(this.body);
|
||||
}
|
||||
|
||||
AffineTransform old = g2d.getTransform();
|
||||
|
||||
Point[] controlPoints = getControlPoints();
|
||||
|
||||
if (this.flip == SymbolFlipping.Y) {
|
||||
g2d.translate(0, controlPoints[0].y);
|
||||
g2d.scale(1, -1);
|
||||
@@ -141,49 +159,80 @@ public abstract class Abstract3LegSymbol extends AbstractComponent<String> {
|
||||
Rectangle2D textRect = fontMetrics.getStringBounds(label, g2d);
|
||||
Rectangle shapeRect = body[0].getBounds().union(body[1].getBounds()).union(body[2].getBounds());
|
||||
|
||||
drawCenteredText(g2d, label, getLabelX(shapeRect, textRect, fontMetrics, outlineMode),
|
||||
if (getMoveLabel()) {
|
||||
StringUtils.drawCenteredText(g2d, label, controlPoints[3].x, controlPoints[3].y, flip == SymbolFlipping.X ? HorizontalAlignment.RIGHT
|
||||
: HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
|
||||
} else {
|
||||
StringUtils.drawCenteredText(g2d, label, getLabelX(shapeRect, textRect, fontMetrics, outlineMode),
|
||||
getLabelY(shapeRect, textRect, fontMetrics, outlineMode), flip == SymbolFlipping.X ? HorizontalAlignment.RIGHT
|
||||
: HorizontalAlignment.LEFT, VerticalAlignment.CENTER);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Point getControlPoint(int index) {
|
||||
return controlPoints[index];
|
||||
return getControlPoints()[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getControlPointCount() {
|
||||
return controlPoints.length;
|
||||
return getControlPoints().length;
|
||||
}
|
||||
|
||||
protected int getLabelX(Rectangle2D shapeRect, Rectangle2D textRect, FontMetrics fontMetrics, boolean outlineMode) {
|
||||
int f = flip == SymbolFlipping.X ? -1 : 1;
|
||||
int d = flip == SymbolFlipping.X ? (int) PIN_SPACING.convertToPixels() / 2 : 0;
|
||||
return controlPoints[0].x + f * (int) (PIN_SPACING.convertToPixels() * 1.5 + d);
|
||||
return getControlPoints()[0].x + f * (int) (PIN_SPACING.convertToPixels() * 1.5 + d);
|
||||
}
|
||||
|
||||
protected int getLabelY(Rectangle2D shapeRect, Rectangle2D textRect, FontMetrics fontMetrics, boolean outlineMode) {
|
||||
return controlPoints[0].y;
|
||||
return getControlPoints()[0].y;
|
||||
}
|
||||
|
||||
private void updateControlPoints() {
|
||||
protected void updateControlPoints() {
|
||||
int pinSpacing = (int) PIN_SPACING.convertToPixels();
|
||||
// Update control points.
|
||||
Point[] controlPoints = getControlPoints();
|
||||
|
||||
int x = controlPoints[0].x;
|
||||
int y = controlPoints[0].y;
|
||||
|
||||
int f = flip == SymbolFlipping.X ? -1 : 1;
|
||||
|
||||
controlPoints[1].x = x + f * pinSpacing * 2;
|
||||
// set default point positions
|
||||
controlPoints[1].x = x + pinSpacing * 2;
|
||||
controlPoints[1].y = y - pinSpacing * 2;
|
||||
|
||||
controlPoints[2].x = x + f * pinSpacing * 2;
|
||||
controlPoints[2].x = x + pinSpacing * 2;
|
||||
controlPoints[2].y = y + pinSpacing * 2;
|
||||
|
||||
controlPoints[3].x = x + (int) (PIN_SPACING.convertToPixels() * 2);
|
||||
controlPoints[3].y = y;
|
||||
|
||||
// apply rotation if needed
|
||||
if (getOrientation() != Orientation.DEFAULT)
|
||||
{
|
||||
Point first = controlPoints[0];
|
||||
double angle = Double.parseDouble(getOrientation().name().replace("_", ""));
|
||||
AffineTransform rotate = AffineTransform.getRotateInstance(Math.toRadians(angle), first.x, first.y);
|
||||
for (int i = 1; i < controlPoints.length; i++) {
|
||||
rotate.transform(controlPoints[i], controlPoints[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// flip at the end
|
||||
if (flip == SymbolFlipping.X) {
|
||||
controlPoints[1].x = controlPoints[0].x - (controlPoints[1].x - controlPoints[0].x);
|
||||
controlPoints[2].x = controlPoints[0].x - (controlPoints[2].x - controlPoints[0].x);
|
||||
controlPoints[3].x = controlPoints[0].x - (controlPoints[3].x - controlPoints[0].x);
|
||||
}
|
||||
if (flip == SymbolFlipping.Y) {
|
||||
controlPoints[1].y = controlPoints[0].y - (controlPoints[1].y - controlPoints[0].y);
|
||||
controlPoints[2].y = controlPoints[0].y - (controlPoints[2].y - controlPoints[0].y);
|
||||
controlPoints[3].y = controlPoints[0].y - (controlPoints[3].y - controlPoints[0].y);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public VisibilityPolicy getControlPointVisibilityPolicy(int index) {
|
||||
return VisibilityPolicy.WHEN_SELECTED;
|
||||
return index < 3 || getMoveLabel() ? VisibilityPolicy.WHEN_SELECTED : VisibilityPolicy.NEVER;
|
||||
}
|
||||
|
||||
@EditableProperty
|
||||
@@ -199,14 +248,25 @@ public abstract class Abstract3LegSymbol extends AbstractComponent<String> {
|
||||
|
||||
@Override
|
||||
public boolean isControlPointSticky(int index) {
|
||||
return true;
|
||||
return index < 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setControlPoint(Point point, int index) {
|
||||
controlPoints[index].setLocation(point);
|
||||
getControlPoints()[index].setLocation(point);
|
||||
|
||||
refreshDrawing();
|
||||
// make sure we have a new drawing
|
||||
body = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPointMoveFreely(int pointIndex) {
|
||||
return pointIndex == 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canControlPointOverlap(int index) {
|
||||
return index >= 3;
|
||||
}
|
||||
|
||||
@EditableProperty
|
||||
@@ -217,7 +277,9 @@ public abstract class Abstract3LegSymbol extends AbstractComponent<String> {
|
||||
public void setFlip(SymbolFlipping flip) {
|
||||
this.flip = flip;
|
||||
|
||||
refreshDrawing();
|
||||
updateControlPoints();
|
||||
// make sure we have a new drawing
|
||||
body = null;
|
||||
}
|
||||
|
||||
@EditableProperty
|
||||
@@ -229,6 +291,15 @@ public abstract class Abstract3LegSymbol extends AbstractComponent<String> {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Moveable Label")
|
||||
public boolean getMoveLabel() {
|
||||
return moveLabel;
|
||||
}
|
||||
|
||||
public void setMoveLabel(boolean moveLabel) {
|
||||
this.moveLabel = moveLabel;
|
||||
}
|
||||
|
||||
@EditableProperty
|
||||
public Display getDisplay() {
|
||||
return display;
|
||||
@@ -249,31 +320,33 @@ public abstract class Abstract3LegSymbol extends AbstractComponent<String> {
|
||||
public void setOrientation(Orientation orientation) {
|
||||
this.orientation = orientation;
|
||||
|
||||
refreshDrawing();
|
||||
}
|
||||
|
||||
protected void refreshDrawing() {
|
||||
updateControlPoints();
|
||||
// make sure we have a new drawing
|
||||
body = null;
|
||||
getBody();
|
||||
}
|
||||
|
||||
protected void applyOrientation(Shape[] body) {
|
||||
if (getOrientation() == Orientation.DEFAULT)
|
||||
return;
|
||||
|
||||
Point first = this.controlPoints[0];
|
||||
Point first = getControlPoints()[0];
|
||||
double angle = Double.parseDouble(getOrientation().name().replace("_", ""));
|
||||
AffineTransform rotate = AffineTransform.getRotateInstance(Math.toRadians(angle), first.x, first.y);
|
||||
for (int i = 1; i < this.controlPoints.length; i++) {
|
||||
rotate.transform(this.controlPoints[i], this.controlPoints[i]);
|
||||
}
|
||||
if (this.body != null) {
|
||||
for (int i = 0; i < this.body.length; i++) {
|
||||
this.body[i] = rotate.createTransformedShape(this.body[i]);
|
||||
|
||||
if (body != null) {
|
||||
for (int i = 0; i < body.length; i++) {
|
||||
body[i] = rotate.createTransformedShape(body[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getControlPointNodeName(int index) {
|
||||
if (index >= 3)
|
||||
return null;
|
||||
return Integer.toString(index + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns transistor shape consisting of 3 parts, in this order: main body, connectors, polarity
|
||||
* arrow.
|
||||
|
||||
@@ -0,0 +1,672 @@
|
||||
/*
|
||||
*
|
||||
* DIY Layout Creator (DIYLC). Copyright (c) 2009-2018 held jointly by the individual authors.
|
||||
*
|
||||
* This file is part of DIYLC.
|
||||
*
|
||||
* DIYLC is free software: you can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* DIYLC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with DIYLC. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.diylc.components;
|
||||
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Composite;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Paint;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Shape;
|
||||
import java.awt.Stroke;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Area;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import java.awt.geom.Line2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
import org.diylc.appframework.miscutils.ConfigurationManager;
|
||||
import org.diylc.awt.ShadedPaint;
|
||||
import org.diylc.awt.StringUtils;
|
||||
import org.diylc.common.Display;
|
||||
import org.diylc.common.HorizontalAlignment;
|
||||
import org.diylc.common.IPlugInPort;
|
||||
import org.diylc.common.LineStyle;
|
||||
import org.diylc.common.ObjectCache;
|
||||
import org.diylc.common.VerticalAlignment;
|
||||
import org.diylc.core.ComponentState;
|
||||
import org.diylc.core.IDrawingObserver;
|
||||
import org.diylc.core.Project;
|
||||
import org.diylc.core.Theme;
|
||||
import org.diylc.core.VisibilityPolicy;
|
||||
import org.diylc.core.annotations.EditableProperty;
|
||||
import org.diylc.core.annotations.PositiveNonZeroMeasureValidator;
|
||||
import org.diylc.core.measures.Size;
|
||||
import org.diylc.core.measures.SizeUnit;
|
||||
import org.diylc.utils.Constants;
|
||||
|
||||
/**
|
||||
* Base class for all leaded components such as resistors or capacitors. Has two control points and
|
||||
* draws leads between them. Also, it positions and draws the shape of the component as specified by
|
||||
* a child class.
|
||||
*
|
||||
* @author Branislav Stojkovic
|
||||
*/
|
||||
public abstract class AbstractLeadedComponent<T> extends AbstractTransparentComponent<T> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static Color LEAD_COLOR = Color.decode("#CCCCCC");
|
||||
public static Color LEAD_COLOR_ICON = LEAD_COLOR.darker().darker();
|
||||
public static Size LEAD_THICKNESS = new Size(0.6d, SizeUnit.mm);
|
||||
public static Size DEFAULT_SIZE = new Size(1d, SizeUnit.in);
|
||||
|
||||
protected Size length;
|
||||
protected Size width;
|
||||
protected Point[] points = new Point[] {new Point((int) (-DEFAULT_SIZE.convertToPixels() / 2), 0),
|
||||
new Point((int) (DEFAULT_SIZE.convertToPixels() / 2), 0), new Point(0, 0)};
|
||||
protected Color bodyColor = Color.white;
|
||||
protected Color borderColor = Color.black;
|
||||
protected Color labelColor = LABEL_COLOR;
|
||||
protected Color leadColor = LEAD_COLOR;
|
||||
protected Display display = Display.NAME;
|
||||
private boolean flipStanding = false;
|
||||
private LabelOriantation labelOriantation = LabelOriantation.Directional;
|
||||
protected boolean moveLabel = false;
|
||||
|
||||
// parameters for adjusting the label control point
|
||||
protected Double gamma = null;
|
||||
protected Double r = null;
|
||||
|
||||
protected AbstractLeadedComponent() {
|
||||
super();
|
||||
try {
|
||||
this.length = getDefaultLength().clone();
|
||||
this.width = getDefaultWidth().clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
// This should never happen because Size supports cloning.
|
||||
} catch (NullPointerException e) {
|
||||
// This will happen if components do not have any shape.
|
||||
}
|
||||
points[2] = calculateLabelPosition(points[0], points[1]);
|
||||
}
|
||||
|
||||
protected boolean IsCopperArea() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected Point[] getPoints() {
|
||||
// convert old points to new
|
||||
if (points.length == 2) {
|
||||
points = new Point[] { points[0], points[1], calculateLabelPosition(points[0], points[1]) };
|
||||
// to make standing components backward compatible and not show a label until the user switches the display to something else
|
||||
if (isStanding())
|
||||
display = Display.NONE;
|
||||
}
|
||||
return points;
|
||||
}
|
||||
|
||||
protected Point calculateLabelPosition(Point point1, Point point2) {
|
||||
double x = (point1.x + point2.x) / 2.0;
|
||||
double y = (point1.y + point2.y) / 2.0;
|
||||
return new Point((int) x, (int) y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project,
|
||||
IDrawingObserver drawingObserver) {
|
||||
if (gamma != null) {
|
||||
// recalculate center position and theta, then adjust label point accordingly, while preserving alpha and p
|
||||
double x = (getPoints()[1].x + getPoints()[0].x) / 2.0;
|
||||
double y = (getPoints()[1].y + getPoints()[0].y) / 2.0;
|
||||
double theta = Math.atan2(getPoints()[1].y - getPoints()[0].y, getPoints()[1].x - getPoints()[0].x);
|
||||
double beta = gamma - (Math.PI / 2 - theta);
|
||||
getPoints()[2].setLocation(x + Math.cos(beta) * r, y + Math.sin(beta) * r);
|
||||
gamma = null;
|
||||
r = null;
|
||||
}
|
||||
|
||||
double distance = getPoints()[0].distance(getPoints()[1]);
|
||||
Shape shape = getBodyShape();
|
||||
// If there's no body, just draw the line connecting the ending points.
|
||||
if (shape == null) {
|
||||
drawLead(g2d, componentState, drawingObserver, IsCopperArea());
|
||||
return;
|
||||
}
|
||||
|
||||
AffineTransform oldTransform = g2d.getTransform();
|
||||
double width;
|
||||
double length;
|
||||
Rectangle shapeRect;
|
||||
double theta = Math.atan2(getPoints()[1].y - getPoints()[0].y, getPoints()[1].x - getPoints()[0].x);
|
||||
|
||||
if (isStanding()) {
|
||||
// When ending points are too close draw the component in standing
|
||||
// mode.
|
||||
width = length = getClosestOdd(this.width.convertToPixels());
|
||||
Shape body =
|
||||
new Ellipse2D.Double((getFlipStanding() ? getPoints()[1] : getPoints()[0]).x - width / 2,
|
||||
(getFlipStanding() ? getPoints()[1] : getPoints()[0]).y - width / 2, width, width);
|
||||
shapeRect = body.getBounds();
|
||||
Composite oldComposite = g2d.getComposite();
|
||||
if (alpha < MAX_ALPHA) {
|
||||
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA));
|
||||
}
|
||||
g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getStandingBodyColor());
|
||||
g2d.fill(body);
|
||||
g2d.setComposite(oldComposite);
|
||||
Color finalBorderColor;
|
||||
if (outlineMode) {
|
||||
Theme theme =
|
||||
(Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME);
|
||||
finalBorderColor =
|
||||
componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR
|
||||
: theme.getOutlineColor();
|
||||
} else {
|
||||
finalBorderColor =
|
||||
componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR
|
||||
: borderColor;
|
||||
}
|
||||
|
||||
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1f));
|
||||
g2d.setColor(finalBorderColor);
|
||||
g2d.draw(body);
|
||||
if (!outlineMode) {
|
||||
drawLead(g2d, componentState, drawingObserver, false);
|
||||
}
|
||||
} else {
|
||||
// Normal mode with component body in the center and two lead parts.
|
||||
shapeRect = shape.getBounds();
|
||||
// Go back to the original transformation to draw leads.
|
||||
if (!outlineMode) {
|
||||
// AffineTransform textTransform = g2d.getTransform();
|
||||
// if (length.convertToPixels() > points[0].distance(points[1]))
|
||||
// {
|
||||
// g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
|
||||
// 0.5f));
|
||||
// }
|
||||
float leadThickness = getLeadThickness();
|
||||
double leadLength = (distance - calculatePinSpacing(shapeRect)) / 2;
|
||||
|
||||
if (shouldShadeLeads()) {
|
||||
Stroke leadStroke = ObjectCache.getInstance().fetchBasicStroke(leadThickness - 1);
|
||||
Color leadColor = getLeadColorForPainting(componentState);
|
||||
|
||||
Area leadArea = new Area();
|
||||
|
||||
int endX = (int) (getPoints()[0].x + Math.cos(theta) * leadLength);
|
||||
int endY = (int) (getPoints()[0].y + Math.sin(theta) * leadLength);
|
||||
Line2D line = new Line2D.Double(getPoints()[0].x, getPoints()[0].y, endX, endY);
|
||||
leadArea.add(new Area(leadStroke.createStrokedShape(line)));
|
||||
|
||||
endX = (int) (getPoints()[1].x + Math.cos(theta - Math.PI) * leadLength);
|
||||
endY = (int) (getPoints()[1].y + Math.sin(theta - Math.PI) * leadLength);
|
||||
line = new Line2D.Double(getPoints()[1].x, getPoints()[1].y, endX, endY);
|
||||
leadArea.add(new Area(leadStroke.createStrokedShape(line)));
|
||||
|
||||
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1f));
|
||||
g2d.setColor(leadColor);
|
||||
g2d.fill(leadArea);
|
||||
g2d.setColor(leadColor.darker());
|
||||
g2d.draw(leadArea);
|
||||
} else {
|
||||
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness));
|
||||
Color leadColor = getLeadColorForPainting(componentState);
|
||||
g2d.setColor(leadColor);
|
||||
drawLeads(g2d, theta, leadLength);
|
||||
}
|
||||
// g2d.setTransform(textTransform);
|
||||
}
|
||||
// Transform graphics to draw the body in the right place and at the
|
||||
// right angle.
|
||||
if (useShapeRectAsPosition()) {
|
||||
width = shapeRect.getHeight();
|
||||
length = shapeRect.getWidth();
|
||||
} else {
|
||||
width = getWidth().convertToPixels();
|
||||
length = getLength().convertToPixels();
|
||||
}
|
||||
g2d.translate((getPoints()[0].x + getPoints()[1].x - length) / 2, (getPoints()[0].y + getPoints()[1].y - width) / 2);
|
||||
g2d.rotate(theta, length / 2, width / 2);
|
||||
// Draw body.
|
||||
Composite oldComposite = g2d.getComposite();
|
||||
if (alpha < MAX_ALPHA) {
|
||||
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA));
|
||||
}
|
||||
if (bodyColor != null) {
|
||||
g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : bodyColor);
|
||||
|
||||
if (!outlineMode && ConfigurationManager.getInstance().readBoolean(IPlugInPort.HI_QUALITY_RENDER_KEY, false)) {
|
||||
Point p1 = new Point((int) (length / 2), 0);
|
||||
Point p2 = new Point((int) (length / 2), (int) width);
|
||||
ShadedPaint paint = theta > 0 && theta < Math.PI ? new ShadedPaint(p2, p1, bodyColor) : new ShadedPaint(p1, p2, bodyColor);
|
||||
Paint oldPaint = g2d.getPaint();
|
||||
g2d.setPaint(paint);
|
||||
g2d.fill(shape);
|
||||
g2d.setPaint(oldPaint);
|
||||
} else {
|
||||
g2d.fill(shape);
|
||||
}
|
||||
}
|
||||
|
||||
Composite newComposite = null;
|
||||
if (!decorateAboveBorder())
|
||||
decorateComponentBody(g2d, outlineMode);
|
||||
else
|
||||
newComposite = g2d.getComposite();
|
||||
|
||||
g2d.setComposite(oldComposite);
|
||||
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(getOutlineStrokeSize()));
|
||||
Color finalBorderColor;
|
||||
if (outlineMode) {
|
||||
Theme theme =
|
||||
(Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME);
|
||||
finalBorderColor =
|
||||
componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR
|
||||
: theme.getOutlineColor();
|
||||
} else {
|
||||
finalBorderColor =
|
||||
componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR
|
||||
: borderColor;
|
||||
}
|
||||
g2d.setColor(finalBorderColor);
|
||||
g2d.draw(shape);
|
||||
|
||||
if (decorateAboveBorder()) {
|
||||
g2d.setComposite(newComposite);
|
||||
decorateComponentBody(g2d, outlineMode);
|
||||
g2d.setComposite(oldComposite);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw label.
|
||||
g2d.setFont(project.getFont());
|
||||
if (useShapeRectAsPosition()) {
|
||||
g2d.translate(shapeRect.x, shapeRect.y);
|
||||
}
|
||||
Color finalLabelColor;
|
||||
if (outlineMode) {
|
||||
Theme theme =
|
||||
(Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME);
|
||||
finalLabelColor =
|
||||
componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED
|
||||
: theme.getOutlineColor();
|
||||
} else {
|
||||
finalLabelColor =
|
||||
componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED
|
||||
: labelColor;
|
||||
}
|
||||
g2d.setColor(finalLabelColor);
|
||||
FontMetrics fontMetrics = g2d.getFontMetrics();
|
||||
String label = "";
|
||||
label = display == Display.NAME ? getName() : (getValue() == null ? "" : getValue().toString());
|
||||
if (display == Display.NONE) {
|
||||
label = "";
|
||||
}
|
||||
if (display == Display.BOTH) {
|
||||
label = getName() + " " + (getValue() == null ? "" : getValue().toString());
|
||||
}
|
||||
Rectangle2D textRect = fontMetrics.getStringBounds(label, g2d);
|
||||
// Don't offset in outline mode.
|
||||
int offset = outlineMode ? 0 : getLabelOffset((int) length, (int) width, (int) textRect.getWidth());
|
||||
|
||||
// Adjust label angle if needed to make sure that it's readable.
|
||||
if ((theta >= Math.PI / 2 && theta <= Math.PI) || (theta < -Math.PI / 2 && theta > -Math.PI)) {
|
||||
g2d.rotate(Math.PI, length / 2, width / 2);
|
||||
theta += Math.PI;
|
||||
offset = -offset;
|
||||
}
|
||||
|
||||
if (getMoveLabel()) {
|
||||
g2d.setTransform(oldTransform);
|
||||
g2d.translate(getPoints()[2].x, getPoints()[2].y);
|
||||
if (getLabelOriantation() != LabelOriantation.Horizontal) {
|
||||
g2d.rotate(theta);
|
||||
}
|
||||
StringUtils.drawCenteredText(g2d, label, offset, 0, HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
|
||||
g2d.setTransform(oldTransform);
|
||||
} else {
|
||||
if (isStanding() || getLabelOriantation() == LabelOriantation.Horizontal) {
|
||||
g2d.setTransform(oldTransform);
|
||||
double x = (getPoints()[0].x + getPoints()[1].x - length) / 2.0;
|
||||
double y = (getPoints()[0].y + getPoints()[1].y - width) / 2.0;
|
||||
g2d.drawString(label, (int) (x + (length - textRect.getWidth()) / 2 + offset),
|
||||
(int)(y + calculateLabelYOffset(shapeRect, textRect, fontMetrics)));
|
||||
} else {
|
||||
g2d.drawString(label, (int) (length - textRect.getWidth()) / 2 + offset,
|
||||
calculateLabelYOffset(shapeRect, textRect, fontMetrics));
|
||||
g2d.setTransform(oldTransform);
|
||||
}
|
||||
}
|
||||
// if (getLabelOriantation() == LabelOriantation.Horizontal) {
|
||||
//
|
||||
// drawCenteredText(g2d, label, getNewPoints()[2].x, getNewPoints()[2].x, HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
|
||||
// g2d.drawString(label, (int) (x + (length - textRect.getWidth()) / 2 + offset),
|
||||
// (int)(y + calculateLabelYCoordinate(shapeRect, textRect, fontMetrics)));
|
||||
// } else {
|
||||
// g2d.drawString(label, (int) (length - textRect.getWidth()) / 2 + offset,
|
||||
// calculateLabelYCoordinate(shapeRect, textRect, fontMetrics));
|
||||
// g2d.setTransform(oldTransform);
|
||||
// }
|
||||
}
|
||||
|
||||
protected boolean isStanding() {
|
||||
return supportsStandingMode() && this.length.convertToPixels() > getPoints()[0].distance(getPoints()[1]);
|
||||
}
|
||||
|
||||
private void drawLeads(Graphics2D g2d, double theta, double leadLength) {
|
||||
double endX = getPoints()[0].x + Math.cos(theta) * leadLength;
|
||||
double endY = getPoints()[0].y + Math.sin(theta) * leadLength;
|
||||
g2d.draw(new Line2D.Double(getPoints()[0].x, getPoints()[0].y, endX, endY));
|
||||
|
||||
endX = getPoints()[1].x + Math.cos(theta - Math.PI) * leadLength;
|
||||
endY = getPoints()[1].y + Math.sin(theta - Math.PI) * leadLength;
|
||||
g2d.draw(new Line2D.Double(getPoints()[1].x, getPoints()[1].y, endX, endY));
|
||||
}
|
||||
|
||||
private void drawLead(Graphics2D g2d, ComponentState componentState, IDrawingObserver observer, boolean isCopperArea) {
|
||||
if (isCopperArea)
|
||||
observer.startTrackingContinuityArea(true);
|
||||
|
||||
float thickness = getLeadThickness();
|
||||
|
||||
Line2D line = new Line2D.Double(getPoints()[0].x, getPoints()[0].y, getPoints()[1].x, getPoints()[1].y);
|
||||
|
||||
if (shouldShadeLeads()) {
|
||||
// for some reason the stroked line gets approx 1px thicker when converted to shape
|
||||
thickness -= 1;
|
||||
}
|
||||
|
||||
Stroke stroke = null;
|
||||
switch (getStyle()) {
|
||||
case SOLID:
|
||||
stroke = ObjectCache.getInstance().fetchBasicStroke(thickness);
|
||||
break;
|
||||
case DASHED:
|
||||
stroke =
|
||||
ObjectCache.getInstance().fetchStroke(thickness, new float[] {thickness * 2, thickness * 4}, thickness * 4, BasicStroke.CAP_SQUARE);
|
||||
break;
|
||||
case DOTTED:
|
||||
stroke = ObjectCache.getInstance().fetchStroke(thickness, new float[] {thickness / 4, thickness * 4}, 0, BasicStroke.CAP_ROUND);
|
||||
break;
|
||||
}
|
||||
|
||||
if (shouldShadeLeads()) {
|
||||
Shape lineShape = stroke.createStrokedShape(line);
|
||||
|
||||
g2d.setColor(getLeadColorForPainting(componentState));
|
||||
g2d.fill(lineShape);
|
||||
|
||||
if (isCopperArea)
|
||||
observer.stopTrackingContinuityArea();
|
||||
|
||||
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1f));
|
||||
Color leadColor = getLeadColorForPainting(componentState);
|
||||
g2d.setColor(leadColor.darker());
|
||||
g2d.draw(lineShape);
|
||||
} else {
|
||||
g2d.setColor(getLeadColorForPainting(componentState));
|
||||
g2d.setStroke(stroke);
|
||||
g2d.draw(line);
|
||||
|
||||
if (isCopperArea)
|
||||
observer.stopTrackingContinuityArea();
|
||||
}
|
||||
}
|
||||
|
||||
protected LineStyle getStyle() {
|
||||
return LineStyle.SOLID;
|
||||
}
|
||||
|
||||
protected void decorateComponentBody(Graphics2D g2d, boolean outlineMode) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
protected boolean decorateAboveBorder() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected int calculateLabelYOffset(Rectangle2D shapeRect, Rectangle2D textRect, FontMetrics fontMetrics) {
|
||||
return (int) (shapeRect.getHeight() - textRect.getHeight()) / 2 + fontMetrics.getAscent();
|
||||
}
|
||||
|
||||
protected boolean shouldShadeLeads() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean supportsStandingMode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected int getLabelOffset(int bodyLength, int bodyWidth, int labelLength) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected float getOutlineStrokeSize() {
|
||||
return 1f;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return default component length.
|
||||
*/
|
||||
protected abstract Size getDefaultLength();
|
||||
|
||||
/**
|
||||
* Returns default component width.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected abstract Size getDefaultWidth();
|
||||
|
||||
/**
|
||||
* @return shape that represents component body. Shape should not be transformed and should be
|
||||
* referenced to (0, 0).
|
||||
*/
|
||||
protected abstract Shape getBodyShape();
|
||||
|
||||
/**
|
||||
* Controls how component shape should be placed relative to start and end point.
|
||||
*
|
||||
* @return <code>true<code> if shape rect should be used to center the component or <code>false</code>
|
||||
* to place the component relative to <code>length</code> and <code>width</code> values.
|
||||
*/
|
||||
protected boolean useShapeRectAsPosition() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return default lead thickness. Override this method to change it.
|
||||
*/
|
||||
protected float getLeadThickness() {
|
||||
return getClosestOdd(LEAD_THICKNESS.convertToPixels());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return default lead color. Override this method to change it.
|
||||
*/
|
||||
protected Color getLeadColorForPainting(ComponentState componentState) {
|
||||
return componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR
|
||||
: getLeadColor();
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Lead Color")
|
||||
public Color getLeadColor() {
|
||||
if (leadColor == null) {
|
||||
leadColor = LEAD_COLOR_ICON;
|
||||
}
|
||||
return leadColor;
|
||||
}
|
||||
|
||||
public void setLeadColor(Color leadColor) {
|
||||
this.leadColor = leadColor;
|
||||
}
|
||||
|
||||
protected int calculatePinSpacing(Rectangle shapeRect) {
|
||||
return shapeRect.width;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getControlPointCount() {
|
||||
return getPoints().length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Point getControlPoint(int index) {
|
||||
return (Point) getPoints()[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isControlPointSticky(int index) {
|
||||
return index < 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VisibilityPolicy getControlPointVisibilityPolicy(int index) {
|
||||
return getMoveLabel() || index < 2 ? VisibilityPolicy.ALWAYS : VisibilityPolicy.NEVER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canControlPointOverlap(int index) {
|
||||
return index >= 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setControlPoint(Point point, int index) {
|
||||
// when moving one of the ending points, try to retain the angle and distance from the center point to label point
|
||||
if (index < 2) {
|
||||
if (gamma == null) {
|
||||
double x = (getPoints()[1].x + getPoints()[0].x) / 2.0;
|
||||
double y = (getPoints()[1].y + getPoints()[0].y) / 2.0;
|
||||
double theta = Math.atan2(getPoints()[1].y - getPoints()[0].y, getPoints()[1].x - getPoints()[0].x);
|
||||
double beta = Math.atan2(getPoints()[2].y - y, getPoints()[2].x - x);
|
||||
gamma = beta + (Math.PI / 2 - theta);
|
||||
r = getPoints()[2].distance(x, y);
|
||||
} else { // in case when we are copy pasting we don't want to recalculate 3rd point position as they will all move in unison
|
||||
// when we moved the first point, gamma and r were initialized, so now we are canceling
|
||||
gamma = null;
|
||||
r = null;
|
||||
}
|
||||
}
|
||||
|
||||
getPoints()[index].setLocation(point);
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Color")
|
||||
public Color getBodyColor() {
|
||||
return bodyColor;
|
||||
}
|
||||
|
||||
public void setBodyColor(Color bodyColor) {
|
||||
this.bodyColor = bodyColor;
|
||||
}
|
||||
|
||||
public Color getStandingBodyColor() {
|
||||
return bodyColor;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Border")
|
||||
public Color getBorderColor() {
|
||||
return borderColor;
|
||||
}
|
||||
|
||||
public void setBorderColor(Color borderColor) {
|
||||
this.borderColor = borderColor;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Length", defaultable = true, validatorClass = PositiveNonZeroMeasureValidator.class)
|
||||
public Size getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
public void setLength(Size length) {
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Width", defaultable = true, validatorClass = PositiveNonZeroMeasureValidator.class)
|
||||
public Size getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public void setWidth(Size width) {
|
||||
this.width = width;
|
||||
}
|
||||
|
||||
@EditableProperty
|
||||
public Display getDisplay() {
|
||||
return display;
|
||||
}
|
||||
|
||||
public void setDisplay(Display display) {
|
||||
this.display = display;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Label Color")
|
||||
public Color getLabelColor() {
|
||||
return labelColor;
|
||||
}
|
||||
|
||||
public void setLabelColor(Color labelColor) {
|
||||
this.labelColor = labelColor;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Label Orientation")
|
||||
public LabelOriantation getLabelOriantation() {
|
||||
if (labelOriantation == null)
|
||||
labelOriantation = LabelOriantation.Directional;
|
||||
return labelOriantation;
|
||||
}
|
||||
|
||||
public void setLabelOriantation(LabelOriantation labelOriantation) {
|
||||
this.labelOriantation = labelOriantation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInternalLinkName(int index1, int index2) {
|
||||
if ((index1 == 0 && index2 == 1) || (index2 == 0 && index1 == 1))
|
||||
return getName();
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this method with @EditableProperty annotation in child classes where standing mode is
|
||||
* supported
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean getFlipStanding() {
|
||||
return flipStanding;
|
||||
}
|
||||
|
||||
public void setFlipStanding(boolean flipStanding) {
|
||||
this.flipStanding = flipStanding;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Moveable Label")
|
||||
public boolean getMoveLabel() {
|
||||
return moveLabel;
|
||||
}
|
||||
|
||||
public void setMoveLabel(boolean moveLabel) {
|
||||
this.moveLabel = moveLabel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getControlPointNodeName(int index) {
|
||||
if (index >= 2)
|
||||
return null;
|
||||
return Integer.toString(index + 1);
|
||||
}
|
||||
|
||||
public enum LabelOriantation {
|
||||
Directional, Horizontal
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package org.diylc.components;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Area;
|
||||
|
||||
import org.diylc.common.ObjectCache;
|
||||
import org.diylc.core.ComponentState;
|
||||
import org.diylc.core.IDrawingObserver;
|
||||
import org.diylc.core.Project;
|
||||
|
||||
|
||||
public abstract class AbstractMultiPartComponent<T> extends AbstractTransparentComponent<T> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public abstract Area[] getBody();
|
||||
|
||||
public void drawSelectionOutline(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project,
|
||||
IDrawingObserver drawingObserver) {
|
||||
if (componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING) {
|
||||
g2d.setColor(SELECTION_COLOR);
|
||||
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1f));
|
||||
g2d.draw(getBodyOutline());
|
||||
}
|
||||
}
|
||||
|
||||
public Area getBodyOutline() {
|
||||
Area[] body = getBody();
|
||||
Area outline = new Area();
|
||||
for (Area b : body)
|
||||
if (b != null)
|
||||
outline.add(b);
|
||||
return outline;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -45,7 +45,7 @@ public abstract class AbstractRadialComponent<T> extends AbstractLeadedComponent
|
||||
|
||||
@Override
|
||||
protected int calculatePinSpacing(Rectangle shapeRect) {
|
||||
return getClosestOdd(getPinSpacing().convertToPixels());
|
||||
return (int) getPinSpacing().convertToPixels();
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Pin spacing")
|
||||
+12
-2
@@ -23,6 +23,7 @@ package org.diylc.components;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Point;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
import org.diylc.common.LabelPosition;
|
||||
@@ -62,7 +63,7 @@ public abstract class AbstractSchematicLeadedSymbol<T> extends AbstractLeadedCom
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int calculateLabelYCoordinate(Rectangle2D shapeRect, Rectangle2D textRect, FontMetrics fontMetrics) {
|
||||
protected int calculateLabelYOffset(Rectangle2D shapeRect, Rectangle2D textRect, FontMetrics fontMetrics) {
|
||||
if (labelPosition == LabelPosition.ABOVE) {
|
||||
return -5;
|
||||
} else {
|
||||
@@ -70,7 +71,16 @@ public abstract class AbstractSchematicLeadedSymbol<T> extends AbstractLeadedCom
|
||||
}
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Label position")
|
||||
@Override
|
||||
protected Point calculateLabelPosition(Point point1, Point point2) {
|
||||
double x = (point1.x + point2.x) / 2.0;
|
||||
double y = (point1.y + point2.y) / 2.0;
|
||||
double theta = Math.atan2(point2.y - point1.y, point2.x - point2.x) - Math.PI / 2;
|
||||
double r = width.convertToPixels() / 2 + LABEL_FONT.getSize() / 2;
|
||||
return new Point((int) (x + Math.cos(theta) * r), (int) (y + Math.sin(theta) * r));
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Label Position")
|
||||
public LabelPosition getLabelPosition() {
|
||||
return labelPosition;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2018 held jointly by the individual authors.
|
||||
|
||||
This file is part of DIYLC.
|
||||
|
||||
DIYLC is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DIYLC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package org.diylc.components;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.awt.geom.Path2D;
|
||||
|
||||
public class RoundedPolygon extends Path2D.Double {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public RoundedPolygon(Point[] points, double[] radiuses) {
|
||||
super();
|
||||
moveTo(points[0].x, points[0].y);
|
||||
for (int i = 0; i < points.length - 1; i++) {
|
||||
Point first = points[i];
|
||||
Point second = points[i + 1 >= points.length ? i + 1 - points.length : i + 1];
|
||||
Point third = points[i + 2 >= points.length ? i + 2 - points.length : i + 2];
|
||||
|
||||
Point p1 = new Point(0, 0);
|
||||
Point p2 = new Point(0, 0);
|
||||
locateTwoPoints(first, second, third, radiuses.length <= i ? radiuses[radiuses.length - 1] : radiuses[i], p1, p2);
|
||||
lineTo(p1.x, p1.y);
|
||||
quadTo(second.x, second.y, p2.x, p2.y);
|
||||
}
|
||||
closePath();
|
||||
}
|
||||
|
||||
private void locateTwoPoints(Point first, Point second, Point third, double radius, Point p1, Point p2) {
|
||||
double d1 = distance(first, second);
|
||||
double d2 = distance(second, third);
|
||||
double t1 = 1 - radius / d1;
|
||||
double t2 = radius / d2;
|
||||
interpolate(first, second, t1, p1);
|
||||
interpolate(second, third, t2, p2);
|
||||
}
|
||||
|
||||
private void interpolate(Point p1, Point p2, double t, Point p) {
|
||||
p.setLocation((int)Math.round(p1.x * (1-t) + p2.x * t), (int)Math.round(p1.y * (1-t) + p2.y * t));
|
||||
}
|
||||
|
||||
private double distance(Point p1, Point p2) {
|
||||
return Math.sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,7 @@ import java.awt.Composite;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Point;
|
||||
|
||||
import org.diylc.awt.StringUtils;
|
||||
import org.diylc.common.HorizontalAlignment;
|
||||
import org.diylc.common.ObjectCache;
|
||||
import org.diylc.common.VerticalAlignment;
|
||||
@@ -59,21 +60,27 @@ public abstract class AbstractBoard extends AbstractTransparentComponent<String>
|
||||
protected Color boardColor = BOARD_COLOR;
|
||||
protected Color borderColor = BORDER_COLOR;
|
||||
protected Color coordinateColor = COORDINATE_COLOR;
|
||||
protected Boolean drawCoordinates = true;
|
||||
protected Boolean drawCoordinates = null;
|
||||
protected CoordinateType xType = CoordinateType.Numbers;
|
||||
protected CoordinateOrigin coordinateOrigin = CoordinateOrigin.Top_Left;
|
||||
protected CoordinateDisplay coordinateDisplay = CoordinateDisplay.One_Side;
|
||||
protected CoordinateType yType = CoordinateType.Letters;
|
||||
|
||||
@Override
|
||||
public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project,
|
||||
IDrawingObserver drawingObserver) {
|
||||
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1));
|
||||
if (componentState != ComponentState.DRAGGING) {
|
||||
|
||||
Composite oldComposite = g2d.getComposite();
|
||||
// render as transparent when dragging
|
||||
int alpha = componentState == ComponentState.DRAGGING ? 0 : this.alpha;
|
||||
if (alpha < MAX_ALPHA) {
|
||||
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA));
|
||||
}
|
||||
g2d.setColor(boardColor);
|
||||
g2d.fillRect(firstPoint.x, firstPoint.y, secondPoint.x - firstPoint.x, secondPoint.y - firstPoint.y);
|
||||
g2d.setComposite(oldComposite);
|
||||
}
|
||||
|
||||
// Do not track any changes that follow because the whole board has been
|
||||
// tracked so far.
|
||||
drawingObserver.stopTracking();
|
||||
@@ -83,25 +90,72 @@ public abstract class AbstractBoard extends AbstractTransparentComponent<String>
|
||||
}
|
||||
|
||||
protected void drawCoordinates(Graphics2D g2d, int spacing, Project project) {
|
||||
if (!getDrawCoordinates())
|
||||
return;
|
||||
Point p = new Point(firstPoint);
|
||||
g2d.setColor(coordinateColor);
|
||||
g2d.setFont(project.getFont().deriveFont(COORDINATE_FONT_SIZE));
|
||||
|
||||
int t = 1;
|
||||
while (p.y < secondPoint.y - spacing) {
|
||||
p.y += spacing;
|
||||
super.drawCenteredText(g2d, getCoordinateLabel(t++), p.x + 2, p.y, HorizontalAlignment.LEFT,
|
||||
VerticalAlignment.CENTER);
|
||||
// The half space is used to do rounding when calculating the range.
|
||||
int halfSpace = spacing / 2;
|
||||
CoordinateOrigin origin = getCoordinateOrigin();
|
||||
|
||||
if (getCoordinateDisplay() != CoordinateDisplay.None) {
|
||||
int range;
|
||||
int yOffset;
|
||||
CoordinateType yType = getyType();
|
||||
Point drawPoint = new Point(firstPoint);
|
||||
|
||||
if (origin == CoordinateOrigin.Top_Left || origin == CoordinateOrigin.Top_Right) {
|
||||
range = (int) ((secondPoint.y - firstPoint.y + halfSpace) / spacing);
|
||||
yOffset = spacing;
|
||||
} else {
|
||||
range = (int) ((secondPoint.y - firstPoint.y + halfSpace) / spacing);
|
||||
yOffset = -spacing;
|
||||
drawPoint.y = secondPoint.y;
|
||||
}
|
||||
|
||||
p = new Point(firstPoint);
|
||||
t = 1;
|
||||
while (p.x < secondPoint.x - spacing) {
|
||||
p.x += spacing;
|
||||
super.drawCenteredText(g2d, Integer.toString(t++), p.x, p.y - 2, HorizontalAlignment.CENTER,
|
||||
VerticalAlignment.TOP);
|
||||
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);
|
||||
|
||||
drawPoint.y += yOffset;
|
||||
StringUtils.drawCenteredText(g2d, label,
|
||||
firstPoint.x + xOffset, drawPoint.y,
|
||||
HorizontalAlignment.LEFT, VerticalAlignment.CENTER);
|
||||
if (getCoordinateDisplay() == CoordinateDisplay.Both_Sides) {
|
||||
StringUtils.drawCenteredText(g2d, label,
|
||||
secondPoint.x - xOffset, drawPoint.y,
|
||||
HorizontalAlignment.RIGHT, VerticalAlignment.CENTER);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (getCoordinateDisplay() != CoordinateDisplay.None) {
|
||||
int range;
|
||||
int xOffset;
|
||||
CoordinateType xType = getxType();
|
||||
Point drawPoint = new Point(firstPoint);
|
||||
|
||||
if (origin == CoordinateOrigin.Top_Left || origin == CoordinateOrigin.Bottom_Left) {
|
||||
range = (int) ((secondPoint.x - firstPoint.x + halfSpace) / spacing);
|
||||
xOffset = spacing;
|
||||
} else {
|
||||
range = (int) ((secondPoint.x - firstPoint.x + halfSpace) / spacing);
|
||||
xOffset = -spacing;
|
||||
drawPoint.x = secondPoint.x;
|
||||
}
|
||||
|
||||
for (int c = 1; c < range; c++) {
|
||||
String label = xType == CoordinateType.Letters ? getCoordinateLabel(c) : Integer.toString(c);
|
||||
|
||||
drawPoint.x += xOffset;
|
||||
StringUtils.drawCenteredText(g2d, label,
|
||||
drawPoint.x, firstPoint.y - 2,
|
||||
HorizontalAlignment.CENTER, VerticalAlignment.TOP);
|
||||
if (getCoordinateDisplay() == CoordinateDisplay.Both_Sides) {
|
||||
StringUtils.drawCenteredText(g2d, label,
|
||||
drawPoint.x, (int) (secondPoint.y - COORDINATE_FONT_SIZE),
|
||||
HorizontalAlignment.CENTER, VerticalAlignment.BOTTOM);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,14 +202,48 @@ public abstract class AbstractBoard extends AbstractTransparentComponent<String>
|
||||
this.borderColor = borderColor;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Draw Coordinates")
|
||||
public boolean getDrawCoordinates() {
|
||||
// Null protection for older files
|
||||
return drawCoordinates == null || drawCoordinates;
|
||||
@EditableProperty(name = "X")
|
||||
public CoordinateType getxType() {
|
||||
if (xType == null)
|
||||
xType = CoordinateType.Numbers;
|
||||
return xType;
|
||||
}
|
||||
|
||||
public void setDrawCoordinates(boolean drawCoordinates) {
|
||||
this.drawCoordinates = drawCoordinates;
|
||||
public void setxType(CoordinateType xType) {
|
||||
this.xType = xType;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Coordinates")
|
||||
public CoordinateDisplay getCoordinateDisplay() {
|
||||
if (coordinateDisplay == null)
|
||||
coordinateDisplay = CoordinateDisplay.One_Side;
|
||||
return coordinateDisplay;
|
||||
}
|
||||
|
||||
public void setCoordinateDisplay(CoordinateDisplay coordinateDisplay) {
|
||||
this.coordinateDisplay = coordinateDisplay;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Coordinate Origin")
|
||||
public CoordinateOrigin getCoordinateOrigin() {
|
||||
if (coordinateOrigin == null)
|
||||
coordinateOrigin = CoordinateOrigin.Top_Left;
|
||||
return coordinateOrigin;
|
||||
}
|
||||
|
||||
public void setCoordinateOrigin(CoordinateOrigin coordinateOrigin) {
|
||||
this.coordinateOrigin = coordinateOrigin;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Y")
|
||||
public CoordinateType getyType() {
|
||||
if (yType == null)
|
||||
yType = CoordinateType.Letters;
|
||||
return yType;
|
||||
}
|
||||
|
||||
public void setyType(CoordinateType yType) {
|
||||
this.yType = yType;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -197,4 +285,26 @@ public abstract class AbstractBoard extends AbstractTransparentComponent<String>
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString().replace('_', ' ');
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
package org.diylc.components.boards;
|
||||
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.Color;
|
||||
import java.awt.Composite;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Shape;
|
||||
@@ -88,9 +89,27 @@ public class BlankBoard extends AbstractBoard {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getDrawCoordinates() {
|
||||
public CoordinateType getxType() {
|
||||
// Override to prevent editing.
|
||||
return super.getDrawCoordinates();
|
||||
return super.getxType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CoordinateDisplay getCoordinateDisplay() {
|
||||
// Override to prevent editing.
|
||||
return super.getCoordinateDisplay();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CoordinateType getyType() {
|
||||
// Override to prevent editing.
|
||||
return super.getyType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color getCoordinateColor() {
|
||||
// Override to prevent editing.
|
||||
return super.getCoordinateColor();
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Shape")
|
||||
@@ -105,6 +124,11 @@ public class BlankBoard extends AbstractBoard {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getControlPointNodeName(int index) {
|
||||
return null;
|
||||
}
|
||||
|
||||
static enum Type {
|
||||
ROUND, SQUARE;
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ import java.awt.Graphics2D;
|
||||
import java.awt.Point;
|
||||
import java.awt.geom.AffineTransform;
|
||||
|
||||
import org.diylc.awt.StringUtils;
|
||||
import org.diylc.common.HorizontalAlignment;
|
||||
import org.diylc.common.ObjectCache;
|
||||
import org.diylc.common.Orientation;
|
||||
@@ -46,7 +47,7 @@ import org.diylc.core.measures.Size;
|
||||
import org.diylc.core.measures.SizeUnit;
|
||||
|
||||
@ComponentDescriptor(name = "Breadboard", category = "Boards", author = "Branislav Stojkovic",
|
||||
description = "Prototyping solderless breadboard", instanceNamePrefix = "BB", stretchable = false,
|
||||
description = "Prototyping solderless breadboard", instanceNamePrefix = "BB",
|
||||
zOrder = IDIYComponent.BOARD, bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, autoEdit = false,
|
||||
keywordPolicy = KeywordPolicy.SHOW_TYPE_NAME)
|
||||
public class Breadboard extends AbstractComponent<Void> {
|
||||
@@ -146,7 +147,7 @@ public class Breadboard extends AbstractComponent<Void> {
|
||||
} else {
|
||||
coordinateX = (int) (point.x + offset + 10.5 * spacing);
|
||||
}
|
||||
drawCenteredText(g2d, new Integer(y + 1).toString(), coordinateX, (int) (point.y + (y + 1) * spacing),
|
||||
StringUtils.drawCenteredText(g2d, new Integer(y + 1).toString(), coordinateX, (int) (point.y + (y + 1) * spacing),
|
||||
section == 0 ? HorizontalAlignment.RIGHT : HorizontalAlignment.LEFT, VerticalAlignment.CENTER);
|
||||
for (int x = 0; x < 5; x++) {
|
||||
int holeX = (int) (point.x + offset + (x + 6) * spacing);
|
||||
@@ -159,9 +160,9 @@ public class Breadboard extends AbstractComponent<Void> {
|
||||
// Draw horizontal labels
|
||||
if (y == 0) {
|
||||
g2d.setColor(COORDINATE_COLOR);
|
||||
drawCenteredText(g2d, new String(new byte[] {(byte) (a + x + 5 * section)}), holeX, (int) (point.y),
|
||||
StringUtils.drawCenteredText(g2d, new String(new byte[] {(byte) (a + x + 5 * section)}), holeX, (int) (point.y),
|
||||
HorizontalAlignment.CENTER, VerticalAlignment.TOP);
|
||||
drawCenteredText(g2d, new String(new byte[] {(byte) (a + x + 5 * section)}), holeX, (int) (point.y
|
||||
StringUtils.drawCenteredText(g2d, new String(new byte[] {(byte) (a + x + 5 * section)}), holeX, (int) (point.y
|
||||
+ spacing * 30 + COORDINATE_FONT_SIZE / 2), HorizontalAlignment.CENTER, VerticalAlignment.TOP);
|
||||
}
|
||||
}
|
||||
@@ -218,7 +219,7 @@ public class Breadboard extends AbstractComponent<Void> {
|
||||
} else {
|
||||
coordinateX = (int) (point.x + offset + 10.5 * spacing);
|
||||
}
|
||||
drawCenteredText(g2d, new Integer(y + 1).toString(), coordinateX, (int) (point.y + (y + 1) * spacing),
|
||||
StringUtils.drawCenteredText(g2d, new Integer(y + 1).toString(), coordinateX, (int) (point.y + (y + 1) * spacing),
|
||||
section == 0 ? HorizontalAlignment.RIGHT : HorizontalAlignment.LEFT, VerticalAlignment.CENTER);
|
||||
// for (int x = 0; x < 5; x++) {
|
||||
int holeX1 = (int) (point.x + offset + 6 * spacing);
|
||||
@@ -314,6 +315,11 @@ public class Breadboard extends AbstractComponent<Void> {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPointMoveFreely(int pointIndex) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("incomplete-switch")
|
||||
@Override
|
||||
public Point getControlPoint(int index) {
|
||||
@@ -366,6 +372,11 @@ public class Breadboard extends AbstractComponent<Void> {
|
||||
@Override
|
||||
public void setValue(Void value) {}
|
||||
|
||||
@Override
|
||||
public String getControlPointNodeName(int index) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public enum BreadboardSize {
|
||||
Half, Full
|
||||
}
|
||||
|
||||
@@ -121,6 +121,11 @@ public class EyeletBoard extends AbstractBoard {
|
||||
this.spacing = spacing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getControlPointNodeName(int index) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawIcon(Graphics2D g2d, int width, int height) {
|
||||
int factor = 32 / width;
|
||||
|
||||
@@ -36,6 +36,7 @@ import org.diylc.core.annotations.BomPolicy;
|
||||
import org.diylc.core.annotations.ComponentDescriptor;
|
||||
import org.diylc.core.annotations.EditableProperty;
|
||||
import org.diylc.core.annotations.KeywordPolicy;
|
||||
import org.diylc.core.annotations.PositiveNonZeroMeasureValidator;
|
||||
import org.diylc.core.measures.Size;
|
||||
import org.diylc.core.measures.SizeUnit;
|
||||
import org.diylc.utils.Constants;
|
||||
@@ -95,7 +96,7 @@ public class MarshallPerfBoard extends AbstractBoard {
|
||||
}
|
||||
}
|
||||
|
||||
@EditableProperty
|
||||
@EditableProperty(validatorClass = PositiveNonZeroMeasureValidator.class)
|
||||
public Size getSpacing() {
|
||||
return spacing;
|
||||
}
|
||||
@@ -104,6 +105,11 @@ public class MarshallPerfBoard extends AbstractBoard {
|
||||
this.spacing = spacing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getControlPointNodeName(int index) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawIcon(Graphics2D g2d, int width, int height) {
|
||||
int factor = 32 / width;
|
||||
|
||||
@@ -36,6 +36,7 @@ import org.diylc.core.annotations.BomPolicy;
|
||||
import org.diylc.core.annotations.ComponentDescriptor;
|
||||
import org.diylc.core.annotations.EditableProperty;
|
||||
import org.diylc.core.annotations.KeywordPolicy;
|
||||
import org.diylc.core.annotations.PositiveNonZeroMeasureValidator;
|
||||
import org.diylc.core.measures.Size;
|
||||
import org.diylc.core.measures.SizeUnit;
|
||||
import org.diylc.utils.Constants;
|
||||
@@ -104,7 +105,7 @@ public class PerfBoard extends AbstractBoard {
|
||||
this.padColor = padColor;
|
||||
}
|
||||
|
||||
@EditableProperty
|
||||
@EditableProperty(validatorClass = PositiveNonZeroMeasureValidator.class)
|
||||
public Size getSpacing() {
|
||||
return spacing;
|
||||
}
|
||||
@@ -113,6 +114,11 @@ public class PerfBoard extends AbstractBoard {
|
||||
this.spacing = spacing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getControlPointNodeName(int index) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawIcon(Graphics2D g2d, int width, int height) {
|
||||
int factor = 32 / width;
|
||||
|
||||
@@ -37,6 +37,7 @@ import org.diylc.common.Orientation;
|
||||
import org.diylc.components.AbstractTransparentComponent;
|
||||
import org.diylc.components.transform.TerminalStripTransformer;
|
||||
import org.diylc.core.ComponentState;
|
||||
import org.diylc.core.IContinuity;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.IDrawingObserver;
|
||||
import org.diylc.core.Project;
|
||||
@@ -45,14 +46,15 @@ import org.diylc.core.VisibilityPolicy;
|
||||
import org.diylc.core.annotations.ComponentDescriptor;
|
||||
import org.diylc.core.annotations.EditableProperty;
|
||||
import org.diylc.core.annotations.KeywordPolicy;
|
||||
import org.diylc.core.annotations.PositiveNonZeroMeasureValidator;
|
||||
import org.diylc.core.measures.Size;
|
||||
import org.diylc.core.measures.SizeUnit;
|
||||
import org.diylc.utils.Constants;
|
||||
|
||||
@ComponentDescriptor(name = "Terminal Strip", author = "Branislav Stojkovic", category = "Boards",
|
||||
instanceNamePrefix = "TS", description = "Row of terminals for point-to-point construction", stretchable = false,
|
||||
instanceNamePrefix = "TS", description = "Row of terminals for point-to-point construction",
|
||||
zOrder = IDIYComponent.BOARD, keywordPolicy = KeywordPolicy.SHOW_TYPE_NAME, transformer = TerminalStripTransformer.class)
|
||||
public class TerminalStrip extends AbstractTransparentComponent<String> {
|
||||
public class TerminalStrip extends AbstractTransparentComponent<String> implements IContinuity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@@ -115,7 +117,7 @@ public class TerminalStrip extends AbstractTransparentComponent<String> {
|
||||
body = null;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Terminal spacing")
|
||||
@EditableProperty(name = "Terminal Spacing", validatorClass = PositiveNonZeroMeasureValidator.class)
|
||||
public Size getTerminalSpacing() {
|
||||
return terminalSpacing;
|
||||
}
|
||||
@@ -127,7 +129,7 @@ public class TerminalStrip extends AbstractTransparentComponent<String> {
|
||||
body = null;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Hole spacing")
|
||||
@EditableProperty(name = "Hole Spacing", validatorClass = PositiveNonZeroMeasureValidator.class)
|
||||
public Size getHoleSpacing() {
|
||||
return holeSpacing;
|
||||
}
|
||||
@@ -139,7 +141,7 @@ public class TerminalStrip extends AbstractTransparentComponent<String> {
|
||||
body = null;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Center terminal")
|
||||
@EditableProperty(name = "Center Terminal")
|
||||
public boolean getCenterHole() {
|
||||
return centerHole;
|
||||
}
|
||||
@@ -151,7 +153,7 @@ public class TerminalStrip extends AbstractTransparentComponent<String> {
|
||||
body = null;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Board width")
|
||||
@EditableProperty(name = "Board Width", validatorClass = PositiveNonZeroMeasureValidator.class)
|
||||
public Size getBoardWidth() {
|
||||
return boardWidth;
|
||||
}
|
||||
@@ -449,4 +451,19 @@ public class TerminalStrip extends AbstractTransparentComponent<String> {
|
||||
public void setBorderColor(Color borderColor) {
|
||||
this.borderColor = borderColor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getControlPointNodeName(int index) {
|
||||
return "TerminalStrip" + index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean arePointsConnected(int index1, int index2) {
|
||||
return Math.abs(index1 - index2) == getTerminalCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPointMoveFreely(int pointIndex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,8 +28,8 @@ import java.awt.Graphics2D;
|
||||
import java.awt.Point;
|
||||
import java.awt.Shape;
|
||||
|
||||
import org.diylc.common.SimpleComponentTransformer;
|
||||
import org.diylc.common.OrientationHV;
|
||||
import org.diylc.common.SimpleComponentTransformer;
|
||||
import org.diylc.core.ComponentState;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.IDrawingObserver;
|
||||
@@ -37,6 +37,7 @@ import org.diylc.core.Project;
|
||||
import org.diylc.core.annotations.ComponentDescriptor;
|
||||
import org.diylc.core.annotations.EditableProperty;
|
||||
import org.diylc.core.annotations.KeywordPolicy;
|
||||
import org.diylc.core.annotations.PositiveNonZeroMeasureValidator;
|
||||
import org.diylc.core.measures.Size;
|
||||
import org.diylc.core.measures.SizeUnit;
|
||||
import org.diylc.utils.Constants;
|
||||
@@ -162,7 +163,7 @@ public class TriPadBoard extends AbstractBoard {
|
||||
}
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Strip color")
|
||||
@EditableProperty(name = "Strip Color")
|
||||
public Color getStripColor() {
|
||||
return stripColor;
|
||||
}
|
||||
@@ -171,7 +172,7 @@ public class TriPadBoard extends AbstractBoard {
|
||||
this.stripColor = padColor;
|
||||
}
|
||||
|
||||
@EditableProperty
|
||||
@EditableProperty(validatorClass = PositiveNonZeroMeasureValidator.class)
|
||||
public Size getSpacing() {
|
||||
return spacing;
|
||||
}
|
||||
@@ -236,4 +237,9 @@ public class TriPadBoard extends AbstractBoard {
|
||||
this.stripSpan = stripSpan;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getControlPointNodeName(int index) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,8 +28,8 @@ import java.awt.Graphics2D;
|
||||
import java.awt.Point;
|
||||
import java.awt.Shape;
|
||||
|
||||
import org.diylc.common.SimpleComponentTransformer;
|
||||
import org.diylc.common.OrientationHV;
|
||||
import org.diylc.common.SimpleComponentTransformer;
|
||||
import org.diylc.core.ComponentState;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.IDrawingObserver;
|
||||
@@ -38,6 +38,7 @@ import org.diylc.core.annotations.BomPolicy;
|
||||
import org.diylc.core.annotations.ComponentDescriptor;
|
||||
import org.diylc.core.annotations.EditableProperty;
|
||||
import org.diylc.core.annotations.KeywordPolicy;
|
||||
import org.diylc.core.annotations.PositiveNonZeroMeasureValidator;
|
||||
import org.diylc.core.measures.Size;
|
||||
import org.diylc.core.measures.SizeUnit;
|
||||
import org.diylc.utils.Constants;
|
||||
@@ -122,7 +123,7 @@ public class VeroBoard extends AbstractBoard {
|
||||
}
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Strip color")
|
||||
@EditableProperty(name = "Strip Color")
|
||||
public Color getStripColor() {
|
||||
return stripColor;
|
||||
}
|
||||
@@ -131,7 +132,7 @@ public class VeroBoard extends AbstractBoard {
|
||||
this.stripColor = padColor;
|
||||
}
|
||||
|
||||
@EditableProperty
|
||||
@EditableProperty(validatorClass = PositiveNonZeroMeasureValidator.class)
|
||||
public Size getSpacing() {
|
||||
return spacing;
|
||||
}
|
||||
@@ -149,6 +150,11 @@ public class VeroBoard extends AbstractBoard {
|
||||
this.orientation = orientation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getControlPointNodeName(int index) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawIcon(Graphics2D g2d, int width, int height) {
|
||||
int factor = 32 / width;
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2018 held jointly by the individual authors.
|
||||
|
||||
This file is part of DIYLC.
|
||||
|
||||
DIYLC is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DIYLC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package org.diylc.components.chassis;
|
||||
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.Composite;
|
||||
import java.awt.Graphics2D;
|
||||
|
||||
import org.diylc.common.ObjectCache;
|
||||
import org.diylc.common.SimpleComponentTransformer;
|
||||
import org.diylc.components.shapes.AbstractShape;
|
||||
import org.diylc.core.ComponentState;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.IDrawingObserver;
|
||||
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.measures.Size;
|
||||
import org.diylc.core.measures.SizeUnit;
|
||||
|
||||
@ComponentDescriptor(name = "Chassis Panel", author = "Branislav Stojkovic", category = "Electro-Mechanical",
|
||||
instanceNamePrefix = "CP", description = "One side of a chassis, with or withouth rounded edges",
|
||||
zOrder = IDIYComponent.CHASSIS, bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, autoEdit = false,
|
||||
transformer = SimpleComponentTransformer.class)
|
||||
public class ChassisPanel extends AbstractShape {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
protected Size edgeRadius = new Size(0d, SizeUnit.mm);
|
||||
|
||||
public ChassisPanel() {
|
||||
this.color = LIGHT_METAL_COLOR;
|
||||
this.borderColor = LIGHT_METAL_COLOR.darker();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project,
|
||||
IDrawingObserver drawingObserver) {
|
||||
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke((int) borderThickness.convertToPixels()));
|
||||
int radius = (int) edgeRadius.convertToPixels();
|
||||
if (componentState != ComponentState.DRAGGING) {
|
||||
Composite oldComposite = g2d.getComposite();
|
||||
if (alpha < MAX_ALPHA) {
|
||||
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA));
|
||||
}
|
||||
g2d.setColor(color);
|
||||
g2d.fillRoundRect(firstPoint.x, firstPoint.y, secondPoint.x - firstPoint.x, secondPoint.y - firstPoint.y, radius,
|
||||
radius);
|
||||
g2d.setComposite(oldComposite);
|
||||
}
|
||||
// Do not track any changes that follow because the whole rect has been
|
||||
// tracked so far.
|
||||
drawingObserver.stopTracking();
|
||||
g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR
|
||||
: borderColor);
|
||||
g2d.drawRoundRect(firstPoint.x, firstPoint.y, secondPoint.x - firstPoint.x, secondPoint.y - firstPoint.y, radius,
|
||||
radius);
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Radius")
|
||||
public Size getEdgeRadius() {
|
||||
return edgeRadius;
|
||||
}
|
||||
|
||||
public void setEdgeRadius(Size edgeRadius) {
|
||||
this.edgeRadius = edgeRadius;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawIcon(Graphics2D g2d, int width, int height) {
|
||||
int factor = 32 / width;
|
||||
g2d.setColor(LIGHT_METAL_COLOR);
|
||||
g2d.fillRect(2 / factor, 4 / factor, width - 4 / factor, height - 8 / factor);
|
||||
g2d.setColor(LIGHT_METAL_COLOR.darker());
|
||||
g2d.drawRect(2 / factor, 4 / factor, width - 4 / factor, height - 8 / factor);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
*
|
||||
* DIY Layout Creator (DIYLC). Copyright (c) 2009-2018 held jointly by the individual authors.
|
||||
*
|
||||
* This file is part of DIYLC.
|
||||
*
|
||||
* DIYLC is free software: you can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* DIYLC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with DIYLC. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.diylc.components.chassis;
|
||||
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.Composite;
|
||||
import java.awt.Graphics2D;
|
||||
|
||||
import org.diylc.common.ObjectCache;
|
||||
import org.diylc.common.SimpleComponentTransformer;
|
||||
import org.diylc.components.shapes.AbstractShape;
|
||||
import org.diylc.core.ComponentState;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.IDrawingObserver;
|
||||
import org.diylc.core.Project;
|
||||
import org.diylc.core.annotations.BomPolicy;
|
||||
import org.diylc.core.annotations.ComponentDescriptor;
|
||||
|
||||
@ComponentDescriptor(name = "Elliptical Cutout", author = "Branislav Stojkovic", category = "Electro-Mechanical",
|
||||
instanceNamePrefix = "ELC", description = "Elliptical chassis cutout", zOrder = IDIYComponent.CHASSIS + 0.1,
|
||||
bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false, transformer = SimpleComponentTransformer.class)
|
||||
public class EllipticalCutout extends AbstractShape {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public EllipticalCutout() {
|
||||
this.borderColor = LIGHT_METAL_COLOR.darker();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project,
|
||||
IDrawingObserver drawingObserver) {
|
||||
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke((int) borderThickness.convertToPixels()));
|
||||
|
||||
if (componentState != ComponentState.DRAGGING) {
|
||||
Composite oldComposite = g2d.getComposite();
|
||||
if (alpha < MAX_ALPHA) {
|
||||
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA));
|
||||
}
|
||||
g2d.setColor(color);
|
||||
g2d.fillOval(firstPoint.x, firstPoint.y, secondPoint.x - firstPoint.x, secondPoint.y - firstPoint.y);
|
||||
g2d.setComposite(oldComposite);
|
||||
}
|
||||
// Do not track any changes that follow because the whole oval has been
|
||||
// tracked so far.
|
||||
drawingObserver.stopTracking();
|
||||
g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR
|
||||
: borderColor);
|
||||
g2d.drawOval(firstPoint.x, firstPoint.y, secondPoint.x - firstPoint.x, secondPoint.y - firstPoint.y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawIcon(Graphics2D g2d, int width, int height) {
|
||||
int factor = 32 / width;
|
||||
g2d.setColor(COLOR);
|
||||
g2d.fillOval(2 / factor, 2 / factor, width - 4 / factor, height - 4 / factor);
|
||||
g2d.setColor(LIGHT_METAL_COLOR.darker());
|
||||
g2d.drawOval(2 / factor, 2 / factor, width - 4 / factor, height - 4 / factor);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
*
|
||||
* DIY Layout Creator (DIYLC). Copyright (c) 2009-2018 held jointly by the individual authors.
|
||||
*
|
||||
* This file is part of DIYLC.
|
||||
*
|
||||
* DIYLC is free software: you can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* DIYLC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with DIYLC. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.diylc.components.chassis;
|
||||
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.Color;
|
||||
import java.awt.Composite;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Point;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.diylc.common.ObjectCache;
|
||||
import org.diylc.common.SimpleComponentTransformer;
|
||||
import org.diylc.components.shapes.AbstractShape;
|
||||
import org.diylc.core.ComponentState;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.IDrawingObserver;
|
||||
import org.diylc.core.Project;
|
||||
import org.diylc.core.annotations.BomPolicy;
|
||||
import org.diylc.core.annotations.ComponentDescriptor;
|
||||
import org.diylc.core.annotations.EditableProperty;
|
||||
|
||||
@ComponentDescriptor(name = "Polygonal Cutout", author = "Branislav Stojkovic", category = "Electro-Mechanical",
|
||||
instanceNamePrefix = "POLYC", description = "Polygonal chassis cutout", zOrder = IDIYComponent.CHASSIS + 0.1,
|
||||
bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false, transformer = SimpleComponentTransformer.class)
|
||||
public class PolygonalCutout extends AbstractShape {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
protected PointCount pointCount = PointCount._4;
|
||||
|
||||
public PolygonalCutout() {
|
||||
super();
|
||||
this.borderColor = LIGHT_METAL_COLOR.darker();
|
||||
this.controlPoints =
|
||||
new Point[] {new Point(0, 0), new Point(0, (int) DEFAULT_HEIGHT.convertToPixels()),
|
||||
new Point((int) DEFAULT_WIDTH.convertToPixels(), (int) DEFAULT_HEIGHT.convertToPixels()),
|
||||
new Point((int) DEFAULT_WIDTH.convertToPixels(), 0)};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project,
|
||||
IDrawingObserver drawingObserver) {
|
||||
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke((int) borderThickness.convertToPixels()));
|
||||
g2d.setColor(color);
|
||||
int[] xPoints = new int[controlPoints.length];
|
||||
int[] yPoints = new int[controlPoints.length];
|
||||
for (int i = 0; i < controlPoints.length; i++) {
|
||||
xPoints[i] = controlPoints[i].x;
|
||||
yPoints[i] = controlPoints[i].y;
|
||||
}
|
||||
|
||||
Composite oldComposite = g2d.getComposite();
|
||||
if (this.alpha < MAX_ALPHA) {
|
||||
g2d.setComposite(AlphaComposite.getInstance(3, 1.0F * this.alpha / MAX_ALPHA));
|
||||
}
|
||||
g2d.fillPolygon(xPoints, yPoints, controlPoints.length);
|
||||
g2d.setComposite(oldComposite);
|
||||
|
||||
// Do not track any changes that follow because the whole board has been
|
||||
// tracked so far.
|
||||
drawingObserver.stopTracking();
|
||||
Color lineColor =
|
||||
componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR
|
||||
: borderColor;
|
||||
g2d.setColor(lineColor);
|
||||
g2d.drawPolygon(xPoints, yPoints, controlPoints.length);
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Edges")
|
||||
public PointCount getPointCount() {
|
||||
return pointCount;
|
||||
}
|
||||
|
||||
public void setPointCount(PointCount pointCount) {
|
||||
if (this.pointCount == pointCount)
|
||||
return;
|
||||
int oldPointCount = Integer.parseInt(this.pointCount.toString());
|
||||
int newPointCount = Integer.parseInt(pointCount.toString());
|
||||
this.controlPoints = Arrays.copyOf(this.controlPoints, newPointCount);
|
||||
if (oldPointCount < newPointCount) {
|
||||
this.controlPoints[newPointCount - 1] = this.controlPoints[oldPointCount - 1];
|
||||
for (int i = oldPointCount - 1; i < newPointCount - 1; i++) {
|
||||
this.controlPoints[i] =
|
||||
new Point((this.controlPoints[i - 1].x + this.controlPoints[newPointCount - 1].x) / 2,
|
||||
(this.controlPoints[i - 1].y + this.controlPoints[newPointCount - 1].y) / 2);
|
||||
}
|
||||
}
|
||||
this.pointCount = pointCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawIcon(Graphics2D g2d, int width, int height) {
|
||||
int factor = 32 / width;
|
||||
g2d.setColor(COLOR);
|
||||
int[] x = {2 / factor, width - 2 / factor, width - 4 / factor, 3 / factor};
|
||||
int[] y = {4 / factor, 2 / factor, height - 5 / factor, height - 2 / factor};
|
||||
g2d.fillPolygon(x, y, 4);
|
||||
g2d.setColor(LIGHT_METAL_COLOR.darker());
|
||||
g2d.drawPolygon(x, y, 4);
|
||||
}
|
||||
|
||||
public enum PointCount {
|
||||
_3, _4, _5, _6, _7, _8;
|
||||
|
||||
public String toString() {
|
||||
return name().substring(1);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
*
|
||||
* DIY Layout Creator (DIYLC). Copyright (c) 2009-2018 held jointly by the individual authors.
|
||||
*
|
||||
* This file is part of DIYLC.
|
||||
*
|
||||
* DIYLC is free software: you can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* DIYLC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with DIYLC. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.diylc.components.chassis;
|
||||
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.Composite;
|
||||
import java.awt.Graphics2D;
|
||||
|
||||
import org.diylc.common.ObjectCache;
|
||||
import org.diylc.common.SimpleComponentTransformer;
|
||||
import org.diylc.components.shapes.AbstractShape;
|
||||
import org.diylc.core.ComponentState;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.IDrawingObserver;
|
||||
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.measures.Size;
|
||||
import org.diylc.core.measures.SizeUnit;
|
||||
|
||||
@ComponentDescriptor(name = "Rectangular Cutout", author = "Branislav Stojkovic", category = "Electro-Mechanical",
|
||||
instanceNamePrefix = "RECTC", description = "Rectangular chassis cutout, with or without rounded edges",
|
||||
zOrder = IDIYComponent.CHASSIS + 0.1, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false,
|
||||
transformer = SimpleComponentTransformer.class)
|
||||
public class RectangularCutout extends AbstractShape {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
protected Size edgeRadius = new Size(0d, SizeUnit.mm);
|
||||
|
||||
public RectangularCutout() {
|
||||
this.borderColor = LIGHT_METAL_COLOR.darker();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project,
|
||||
IDrawingObserver drawingObserver) {
|
||||
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke((int) borderThickness.convertToPixels()));
|
||||
int radius = (int) edgeRadius.convertToPixels();
|
||||
if (componentState != ComponentState.DRAGGING) {
|
||||
Composite oldComposite = g2d.getComposite();
|
||||
if (alpha < MAX_ALPHA) {
|
||||
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA));
|
||||
}
|
||||
g2d.setColor(color);
|
||||
g2d.fillRoundRect(firstPoint.x, firstPoint.y, secondPoint.x - firstPoint.x, secondPoint.y - firstPoint.y, radius,
|
||||
radius);
|
||||
g2d.setComposite(oldComposite);
|
||||
}
|
||||
// Do not track any changes that follow because the whole rect has been
|
||||
// tracked so far.
|
||||
drawingObserver.stopTracking();
|
||||
g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR
|
||||
: borderColor);
|
||||
g2d.drawRoundRect(firstPoint.x, firstPoint.y, secondPoint.x - firstPoint.x, secondPoint.y - firstPoint.y, radius,
|
||||
radius);
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Radius")
|
||||
public Size getEdgeRadius() {
|
||||
return edgeRadius;
|
||||
}
|
||||
|
||||
public void setEdgeRadius(Size edgeRadius) {
|
||||
this.edgeRadius = edgeRadius;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawIcon(Graphics2D g2d, int width, int height) {
|
||||
int factor = 32 / width;
|
||||
g2d.setColor(COLOR);
|
||||
g2d.fillRect(2 / factor, 4 / factor, width - 4 / factor, height - 8 / factor);
|
||||
g2d.setColor(LIGHT_METAL_COLOR.darker());
|
||||
g2d.drawRect(2 / factor, 4 / factor, width - 4 / factor, height - 8 / factor);
|
||||
}
|
||||
}
|
||||
@@ -23,11 +23,15 @@ package org.diylc.components.connectivity;
|
||||
|
||||
public enum AWG {
|
||||
|
||||
_8, _10, _12, _14, _16, _18, _20, _22, _24, _26, _28, _30;
|
||||
_8, _10, _12, _14, _16, _18, _20, _22, _24, _26, _28, _30, _32, _34, _36;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "#" + name().replace("_", "");
|
||||
return "#" + name().replace("_", "") + " (" + String.format("%1$,.2f", diameterIn() * 25.4) + "mm / " + String.format("%1$,.5f", diameterIn()) + "in)";
|
||||
}
|
||||
|
||||
public double diameterIn() {
|
||||
return Math.pow(Math.E, -1.12436 - 0.11594 * getValue());
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
|
||||
@@ -21,9 +21,9 @@ import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Shape;
|
||||
|
||||
import org.diylc.common.SimpleComponentTransformer;
|
||||
import org.diylc.common.ObjectCache;
|
||||
import org.diylc.common.PCBLayer;
|
||||
import org.diylc.common.SimpleComponentTransformer;
|
||||
import org.diylc.components.AbstractLeadedComponent;
|
||||
import org.diylc.core.ComponentState;
|
||||
import org.diylc.core.CreationMethod;
|
||||
@@ -162,4 +162,14 @@ public class CopperTrace extends AbstractLeadedComponent<Void> {
|
||||
protected boolean IsCopperArea() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getControlPointNodeName(int index) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean getMoveLabel() {
|
||||
// override to disable edit
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Path2D;
|
||||
|
||||
import org.diylc.common.LineStyle;
|
||||
import org.diylc.common.ObjectCache;
|
||||
import org.diylc.common.PCBLayer;
|
||||
import org.diylc.common.SimpleComponentTransformer;
|
||||
@@ -105,4 +106,14 @@ public class CurvedTrace extends AbstractCurvedComponent<Void> {
|
||||
public void setAlpha(Byte alpha) {
|
||||
super.setAlpha(alpha);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LineStyle getStyle() {
|
||||
return super.getStyle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getControlPointNodeName(int index) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ import org.diylc.core.measures.Size;
|
||||
import org.diylc.core.measures.SizeUnit;
|
||||
|
||||
@ComponentDescriptor(name = "Cut Line", category = "Connectivity", author = "Branislav Stojkovic",
|
||||
description = "Cut line", instanceNamePrefix = "CL", stretchable = false, zOrder = IDIYComponent.COMPONENT,
|
||||
description = "Cut line", instanceNamePrefix = "CL", zOrder = IDIYComponent.COMPONENT,
|
||||
bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false, transformer = SimpleComponentTransformer.class)
|
||||
public class CutLine extends AbstractTransparentComponent<Void> {
|
||||
|
||||
@@ -157,4 +157,9 @@ public class CutLine extends AbstractTransparentComponent<Void> {
|
||||
|
||||
@Override
|
||||
public void setValue(Void value) {}
|
||||
|
||||
@Override
|
||||
public String getControlPointNodeName(int index) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,11 +35,12 @@ import org.diylc.core.VisibilityPolicy;
|
||||
import org.diylc.core.annotations.BomPolicy;
|
||||
import org.diylc.core.annotations.ComponentDescriptor;
|
||||
import org.diylc.core.annotations.EditableProperty;
|
||||
import org.diylc.core.annotations.PositiveNonZeroMeasureValidator;
|
||||
import org.diylc.core.measures.Size;
|
||||
import org.diylc.core.measures.SizeUnit;
|
||||
|
||||
@ComponentDescriptor(name = "Dot", category = "Connectivity", author = "Branislav Stojkovic",
|
||||
description = "Connector dot", instanceNamePrefix = "Dot", stretchable = false, zOrder = IDIYComponent.COMPONENT,
|
||||
description = "Connector dot", instanceNamePrefix = "Dot", zOrder = IDIYComponent.COMPONENT,
|
||||
bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false, transformer = SimpleComponentTransformer.class)
|
||||
public class Dot extends AbstractComponent<Void> {
|
||||
|
||||
@@ -71,7 +72,7 @@ public class Dot extends AbstractComponent<Void> {
|
||||
g2d.fillOval((width - diameter) / 2, (height - diameter) / 2, diameter, diameter);
|
||||
}
|
||||
|
||||
@EditableProperty
|
||||
@EditableProperty(validatorClass = PositiveNonZeroMeasureValidator.class)
|
||||
public Size getSize() {
|
||||
return size;
|
||||
}
|
||||
@@ -126,4 +127,9 @@ public class Dot extends AbstractComponent<Void> {
|
||||
|
||||
@Override
|
||||
public void setValue(Void value) {}
|
||||
|
||||
@Override
|
||||
public String getControlPointNodeName(int index) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Point;
|
||||
|
||||
import org.diylc.common.ObjectCache;
|
||||
import org.diylc.common.SimpleComponentTransformer;
|
||||
import org.diylc.components.AbstractComponent;
|
||||
import org.diylc.core.ComponentState;
|
||||
@@ -36,12 +37,14 @@ import org.diylc.core.annotations.BomPolicy;
|
||||
import org.diylc.core.annotations.ComponentDescriptor;
|
||||
import org.diylc.core.annotations.EditableProperty;
|
||||
import org.diylc.core.annotations.KeywordPolicy;
|
||||
import org.diylc.core.annotations.PositiveMeasureValidator;
|
||||
import org.diylc.core.annotations.PositiveNonZeroMeasureValidator;
|
||||
import org.diylc.core.measures.Size;
|
||||
import org.diylc.core.measures.SizeUnit;
|
||||
import org.diylc.utils.Constants;
|
||||
|
||||
@ComponentDescriptor(name = "Eyelet", category = "Connectivity", author = "Branislav Stojkovic",
|
||||
description = "Eyelet or turret terminal", instanceNamePrefix = "Eyelet", stretchable = false,
|
||||
description = "Eyelet or turret terminal", instanceNamePrefix = "Eyelet",
|
||||
zOrder = IDIYComponent.TRACE + 0.1, bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, autoEdit = false,
|
||||
keywordPolicy = KeywordPolicy.SHOW_TYPE_NAME, transformer = SimpleComponentTransformer.class)
|
||||
public class Eyelet extends AbstractComponent<String> {
|
||||
@@ -66,6 +69,7 @@ public class Eyelet extends AbstractComponent<String> {
|
||||
}
|
||||
int diameter = getClosestOdd((int) size.convertToPixels());
|
||||
int holeDiameter = getClosestOdd((int) holeSize.convertToPixels());
|
||||
g2d.setStroke(ObjectCache.getInstance().fetchZoomableStroke(1f));
|
||||
g2d.setColor(color);
|
||||
drawingObserver.startTrackingContinuityArea(true);
|
||||
g2d.fillOval(point.x - diameter / 2, point.y - diameter / 2, diameter, diameter);
|
||||
@@ -94,7 +98,7 @@ public class Eyelet extends AbstractComponent<String> {
|
||||
g2d.drawOval((width - holeDiameter) / 2, (height - holeDiameter) / 2, holeDiameter, holeDiameter);
|
||||
}
|
||||
|
||||
@EditableProperty
|
||||
@EditableProperty(validatorClass = PositiveNonZeroMeasureValidator.class)
|
||||
public Size getSize() {
|
||||
return size;
|
||||
}
|
||||
@@ -103,7 +107,7 @@ public class Eyelet extends AbstractComponent<String> {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Hole size")
|
||||
@EditableProperty(name = "Hole Size", validatorClass = PositiveMeasureValidator.class)
|
||||
public Size getHoleSize() {
|
||||
return holeSize;
|
||||
}
|
||||
@@ -161,4 +165,9 @@ public class Eyelet extends AbstractComponent<String> {
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getControlPointNodeName(int index) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,6 +161,11 @@ public class GroundFill extends AbstractComponent<Void> {
|
||||
@Override
|
||||
public void setValue(Void value) {}
|
||||
|
||||
@Override
|
||||
public String getControlPointNodeName(int index) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawIcon(Graphics2D g2d, int width, int height) {
|
||||
int factor = 32 / width;
|
||||
|
||||
@@ -17,8 +17,10 @@
|
||||
*/
|
||||
package org.diylc.components.connectivity;
|
||||
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Shape;
|
||||
import java.awt.Stroke;
|
||||
import java.awt.geom.Path2D;
|
||||
|
||||
@@ -26,6 +28,7 @@ import org.diylc.common.ObjectCache;
|
||||
import org.diylc.common.SimpleComponentTransformer;
|
||||
import org.diylc.components.AbstractCurvedComponent;
|
||||
import org.diylc.core.ComponentState;
|
||||
import org.diylc.core.IContinuity;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.IDrawingObserver;
|
||||
import org.diylc.core.annotations.BomPolicy;
|
||||
@@ -36,16 +39,20 @@ import org.diylc.utils.Constants;
|
||||
@ComponentDescriptor(name = "Hookup Wire", author = "Branislav Stojkovic", category = "Connectivity",
|
||||
instanceNamePrefix = "W", description = "Flexible wire with two control points", zOrder = IDIYComponent.COMPONENT,
|
||||
flexibleZOrder = true, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false,
|
||||
transformer = SimpleComponentTransformer.class, continuity = true)
|
||||
public class HookupWire extends AbstractCurvedComponent<Void> {
|
||||
transformer = SimpleComponentTransformer.class)
|
||||
public class HookupWire extends AbstractCurvedComponent<Void> implements IContinuity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static Color COLOR = Color.green;
|
||||
public static Color STRIPE_COLOR = Color.yellow;
|
||||
public static double INSULATION_THICKNESS_PCT = 0.3;
|
||||
|
||||
protected AWG gauge = AWG._22;
|
||||
|
||||
protected boolean striped = false;
|
||||
protected Color stripeColor = STRIPE_COLOR;
|
||||
|
||||
@Override
|
||||
protected Color getDefaultColor() {
|
||||
return COLOR;
|
||||
@@ -53,11 +60,10 @@ public class HookupWire extends AbstractCurvedComponent<Void> {
|
||||
|
||||
@Override
|
||||
protected void drawCurve(Path2D curve, Graphics2D g2d, ComponentState componentState, IDrawingObserver drawingObserver) {
|
||||
int thickness =
|
||||
(int) (Math.pow(Math.E, -1.12436 - 0.11594 * gauge.getValue()) * Constants.PIXELS_PER_INCH * (1 + 2 * INSULATION_THICKNESS_PCT));
|
||||
int thickness = (int) (gauge.diameterIn() * Constants.PIXELS_PER_INCH * (1 + 2 * INSULATION_THICKNESS_PCT)) - 1;
|
||||
Color curveColor =
|
||||
componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR
|
||||
: color.darker();
|
||||
: color;
|
||||
g2d.setColor(curveColor);
|
||||
Stroke stroke = null;
|
||||
switch (getStyle()) {
|
||||
@@ -66,30 +72,28 @@ public class HookupWire extends AbstractCurvedComponent<Void> {
|
||||
break;
|
||||
case DASHED:
|
||||
stroke =
|
||||
ObjectCache.getInstance().fetchStroke(thickness, new float[] {thickness * 2, thickness * 3}, thickness * 4);
|
||||
ObjectCache.getInstance().fetchStroke(thickness, new float[] {thickness * 2, thickness * 3}, thickness * 4, BasicStroke.CAP_SQUARE);
|
||||
break;
|
||||
case DOTTED:
|
||||
stroke = ObjectCache.getInstance().fetchStroke(thickness, new float[] {thickness / 4, thickness * 3}, 0);
|
||||
stroke = ObjectCache.getInstance().fetchStroke(thickness, new float[] {thickness / 4, thickness * 3}, 0, BasicStroke.CAP_ROUND);
|
||||
break;
|
||||
}
|
||||
g2d.setStroke(stroke);
|
||||
g2d.draw(curve);
|
||||
Shape s = stroke.createStrokedShape(curve);
|
||||
g2d.fill(s);
|
||||
|
||||
if (getStriped()) {
|
||||
stroke = ObjectCache.getInstance().fetchStroke(thickness, new float[] { thickness / 2, thickness * 2 }, thickness * 10, BasicStroke.CAP_BUTT);
|
||||
Shape stripe = stroke.createStrokedShape(curve);
|
||||
g2d.setColor(getStripeColor());
|
||||
drawingObserver.stopTracking();
|
||||
g2d.fill(stripe);
|
||||
drawingObserver.startTracking();
|
||||
}
|
||||
|
||||
if (componentState == ComponentState.NORMAL) {
|
||||
g2d.setColor(color);
|
||||
switch (getStyle()) {
|
||||
case SOLID:
|
||||
stroke = ObjectCache.getInstance().fetchBasicStroke(thickness - 2);
|
||||
break;
|
||||
case DASHED:
|
||||
stroke =
|
||||
ObjectCache.getInstance().fetchStroke(thickness - 2, new float[] {thickness * 2, thickness * 3},
|
||||
thickness * 4);
|
||||
break;
|
||||
case DOTTED:
|
||||
stroke = ObjectCache.getInstance().fetchStroke(thickness - 2, new float[] {thickness / 4, thickness * 3}, 0);
|
||||
}
|
||||
g2d.setStroke(stroke);
|
||||
g2d.draw(curve);
|
||||
g2d.setColor(color.darker());
|
||||
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1f));
|
||||
g2d.draw(s);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,4 +113,29 @@ public class HookupWire extends AbstractCurvedComponent<Void> {
|
||||
|
||||
@Override
|
||||
public void setValue(Void value) {}
|
||||
|
||||
@EditableProperty(name = "Stripe")
|
||||
public boolean getStriped() {
|
||||
return striped;
|
||||
}
|
||||
|
||||
public void setStriped(boolean striped) {
|
||||
this.striped = striped;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Stripe Color")
|
||||
public Color getStripeColor() {
|
||||
if (stripeColor == null)
|
||||
stripeColor = STRIPE_COLOR;
|
||||
return stripeColor;
|
||||
}
|
||||
|
||||
public void setStripeColor(Color stripeColor) {
|
||||
this.stripeColor = stripeColor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean arePointsConnected(int index1, int index2) {
|
||||
return Math.abs(index1 - index2) == getControlPointCount() - 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import org.diylc.common.SimpleComponentTransformer;
|
||||
import org.diylc.components.AbstractLeadedComponent;
|
||||
import org.diylc.core.ComponentState;
|
||||
import org.diylc.core.CreationMethod;
|
||||
import org.diylc.core.IContinuity;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.annotations.BomPolicy;
|
||||
import org.diylc.core.annotations.ComponentDescriptor;
|
||||
@@ -41,8 +42,8 @@ import org.diylc.core.measures.Size;
|
||||
@ComponentDescriptor(name = "Jumper", author = "Branislav Stojkovic", category = "Connectivity",
|
||||
creationMethod = CreationMethod.POINT_BY_POINT, instanceNamePrefix = "J", description = "",
|
||||
zOrder = IDIYComponent.COMPONENT, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false,
|
||||
transformer = SimpleComponentTransformer.class, continuity = true)
|
||||
public class Jumper extends AbstractLeadedComponent<Void> {
|
||||
transformer = SimpleComponentTransformer.class)
|
||||
public class Jumper extends AbstractLeadedComponent<Void> implements IContinuity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@@ -157,4 +158,14 @@ public class Jumper extends AbstractLeadedComponent<Void> {
|
||||
public Display getDisplay() {
|
||||
return super.getDisplay();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean arePointsConnected(int index1, int index2) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean getMoveLabel() {
|
||||
// override to disable edit
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,10 +21,14 @@
|
||||
*/
|
||||
package org.diylc.components.connectivity;
|
||||
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Point;
|
||||
import java.awt.Polygon;
|
||||
import java.awt.Shape;
|
||||
import java.awt.Stroke;
|
||||
import java.awt.geom.AffineTransform;
|
||||
|
||||
import org.diylc.common.Display;
|
||||
import org.diylc.common.LineStyle;
|
||||
@@ -40,9 +44,10 @@ import org.diylc.core.annotations.BomPolicy;
|
||||
import org.diylc.core.annotations.ComponentDescriptor;
|
||||
import org.diylc.core.annotations.EditableProperty;
|
||||
import org.diylc.core.measures.Size;
|
||||
import org.diylc.core.measures.SizeUnit;
|
||||
|
||||
@ComponentDescriptor(name = "Line", author = "Branislav Stojkovic", category = "Shapes",
|
||||
creationMethod = CreationMethod.POINT_BY_POINT, instanceNamePrefix = "LN", description = "",
|
||||
creationMethod = CreationMethod.POINT_BY_POINT, instanceNamePrefix = "LN", description = "Line with optional arrows",
|
||||
zOrder = IDIYComponent.COMPONENT, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false,
|
||||
transformer = SimpleComponentTransformer.class)
|
||||
public class Line extends AbstractLeadedComponent<Void> {
|
||||
@@ -53,6 +58,12 @@ public class Line extends AbstractLeadedComponent<Void> {
|
||||
|
||||
private Color color = COLOR;
|
||||
protected LineStyle style = LineStyle.SOLID;
|
||||
private Size thickness = new Size(1d, SizeUnit.px);
|
||||
private Size arrowSize = new Size(5d, SizeUnit.px);
|
||||
private Polygon arrow = null;
|
||||
private AffineTransform arrowTx = new AffineTransform();
|
||||
private boolean arrowStart = false;
|
||||
private boolean arrowEnd = false;
|
||||
|
||||
@Override
|
||||
public void drawIcon(Graphics2D g2d, int width, int height) {
|
||||
@@ -64,22 +75,63 @@ public class Line extends AbstractLeadedComponent<Void> {
|
||||
@Override
|
||||
public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project,
|
||||
IDrawingObserver drawingObserver) {
|
||||
float thickness = 1f;
|
||||
float thickness = (float) getThickness().convertToPixels();
|
||||
Stroke stroke = null;
|
||||
switch (getStyle()) {
|
||||
case SOLID:
|
||||
stroke = ObjectCache.getInstance().fetchBasicStroke(thickness);
|
||||
stroke = ObjectCache.getInstance().fetchZoomableStroke(thickness);
|
||||
break;
|
||||
case DASHED:
|
||||
stroke = ObjectCache.getInstance().fetchStroke(thickness, new float[] {thickness * 2}, thickness * 4);
|
||||
stroke = ObjectCache.getInstance().fetchStroke(thickness, new float[] {thickness * 2, thickness * 4}, thickness * 4, BasicStroke.CAP_SQUARE);
|
||||
break;
|
||||
case DOTTED:
|
||||
stroke = ObjectCache.getInstance().fetchStroke(thickness, new float[] {thickness / 4, thickness * 3}, 0);
|
||||
stroke = ObjectCache.getInstance().fetchStroke(thickness, new float[] {thickness, thickness * 5}, 0, BasicStroke.CAP_ROUND);
|
||||
break;
|
||||
}
|
||||
g2d.setStroke(stroke);
|
||||
g2d.setColor(color);
|
||||
g2d.drawLine(getControlPoint(0).x, getControlPoint(0).y, getControlPoint(1).x, getControlPoint(1).y);
|
||||
g2d.setColor(componentState == ComponentState.SELECTED ? SELECTION_COLOR : color);
|
||||
|
||||
Point startPoint = new Point(getControlPoint(0));
|
||||
Point endPoint = new Point(getControlPoint(1));
|
||||
|
||||
if (arrowStart) {
|
||||
arrowTx.setToIdentity();
|
||||
double angle = Math.atan2(getControlPoint(1).y - getControlPoint(0).y, getControlPoint(1).x - getControlPoint(0).x);
|
||||
arrowTx.translate(getControlPoint(0).x, getControlPoint(0).y);
|
||||
arrowTx.rotate((angle + Math.PI / 2d));
|
||||
AffineTransform oldTx = g2d.getTransform();
|
||||
g2d.transform(arrowTx);
|
||||
g2d.fill(getArrow());
|
||||
g2d.setTransform(oldTx);
|
||||
|
||||
// make the line slightly shorter so line end doesn't overlap with the arrow
|
||||
double distance = distance(startPoint, endPoint);
|
||||
interpolate(startPoint, endPoint, getArrowSize().convertToPixels() * 0.9 / distance, startPoint);
|
||||
}
|
||||
if (arrowEnd) {
|
||||
arrowTx.setToIdentity();
|
||||
double angle = Math.atan2(getControlPoint(1).y - getControlPoint(0).y, getControlPoint(1).x - getControlPoint(0).x);
|
||||
arrowTx.translate(getControlPoint(1).x, getControlPoint(1).y);
|
||||
arrowTx.rotate((angle - Math.PI / 2d));
|
||||
AffineTransform oldTx = g2d.getTransform();
|
||||
g2d.transform(arrowTx);
|
||||
g2d.fill(getArrow());
|
||||
g2d.setTransform(oldTx);
|
||||
|
||||
// make the line slightly shorter so line end doesn't overlap with the arrow
|
||||
double distance = distance(startPoint, endPoint);
|
||||
interpolate(endPoint, startPoint, getArrowSize().convertToPixels() * 0.9 / distance, endPoint);
|
||||
}
|
||||
|
||||
g2d.drawLine(startPoint.x, startPoint.y, endPoint.x, endPoint.y);
|
||||
}
|
||||
|
||||
private void interpolate(Point p1, Point p2, double t, Point p) {
|
||||
p.setLocation((int)Math.round(p1.x * (1-t) + p2.x * t), (int)Math.round(p1.y * (1-t) + p2.y * t));
|
||||
}
|
||||
|
||||
private double distance(Point p1, Point p2) {
|
||||
return Math.sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -88,6 +140,40 @@ public class Line extends AbstractLeadedComponent<Void> {
|
||||
: color;
|
||||
}
|
||||
|
||||
public Polygon getArrow() {
|
||||
if (arrow == null) {
|
||||
arrow = new Polygon();
|
||||
int t = (int) getArrowSize().convertToPixels();
|
||||
arrow.addPoint(0, 0);
|
||||
arrow.addPoint(-t, -t * 2);
|
||||
arrow.addPoint(t, -t * 2);
|
||||
}
|
||||
return arrow;
|
||||
}
|
||||
|
||||
@EditableProperty
|
||||
public Size getThickness() {
|
||||
if (thickness == null)
|
||||
thickness = new Size(1d, SizeUnit.px);
|
||||
return thickness;
|
||||
}
|
||||
|
||||
public void setThickness(Size thickness) {
|
||||
this.thickness = thickness;
|
||||
}
|
||||
|
||||
@EditableProperty
|
||||
public Size getArrowSize() {
|
||||
if (arrowSize == null)
|
||||
arrowSize = thickness = new Size(1d, SizeUnit.px);
|
||||
return arrowSize;
|
||||
}
|
||||
|
||||
public void setArrowSize(Size arrowSize) {
|
||||
this.arrowSize = arrowSize;
|
||||
arrow = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color getLeadColor() {
|
||||
return super.getLeadColor();
|
||||
@@ -113,6 +199,24 @@ public class Line extends AbstractLeadedComponent<Void> {
|
||||
this.style = style;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Start Arrow")
|
||||
public boolean getArrowStart() {
|
||||
return arrowStart;
|
||||
}
|
||||
|
||||
public void setArrowStart(boolean arrowStart) {
|
||||
this.arrowStart = arrowStart;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "End Arrow")
|
||||
public boolean getArrowEnd() {
|
||||
return arrowEnd;
|
||||
}
|
||||
|
||||
public void setArrowEnd(boolean arrowEnd) {
|
||||
this.arrowEnd = arrowEnd;
|
||||
}
|
||||
|
||||
public Color getBodyColor() {
|
||||
return super.getBodyColor();
|
||||
}
|
||||
@@ -160,6 +264,11 @@ public class Line extends AbstractLeadedComponent<Void> {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getControlPointNodeName(int index) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public Color getLabelColor() {
|
||||
@@ -177,4 +286,10 @@ public class Line extends AbstractLeadedComponent<Void> {
|
||||
public Display getDisplay() {
|
||||
return super.getDisplay();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public org.diylc.components.AbstractLeadedComponent.LabelOriantation getLabelOriantation() {
|
||||
return super.getLabelOriantation();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,23 +1,19 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2018 held jointly by the individual authors.
|
||||
|
||||
This file is part of DIYLC.
|
||||
|
||||
DIYLC is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DIYLC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*
|
||||
* DIY Layout Creator (DIYLC). Copyright (c) 2009-2018 held jointly by the individual authors.
|
||||
*
|
||||
* This file is part of DIYLC.
|
||||
*
|
||||
* DIYLC is free software: you can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* DIYLC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with DIYLC. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.diylc.components.connectivity;
|
||||
|
||||
@@ -40,12 +36,13 @@ import org.diylc.core.annotations.ComponentDescriptor;
|
||||
import org.diylc.core.annotations.EditableProperty;
|
||||
import org.diylc.core.annotations.KeywordPolicy;
|
||||
import org.diylc.core.annotations.PositiveMeasureValidator;
|
||||
import org.diylc.core.annotations.PositiveNonZeroMeasureValidator;
|
||||
import org.diylc.core.measures.Size;
|
||||
import org.diylc.core.measures.SizeUnit;
|
||||
import org.diylc.utils.Constants;
|
||||
|
||||
@ComponentDescriptor(name = "Solder Pad", category = "Connectivity", author = "Branislav Stojkovic",
|
||||
description = "Copper solder pad, round or square", instanceNamePrefix = "Pad", stretchable = false,
|
||||
description = "Copper solder pad, round or square", instanceNamePrefix = "Pad",
|
||||
zOrder = IDIYComponent.TRACE + 0.1, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false,
|
||||
keywordPolicy = KeywordPolicy.SHOW_TAG, keywordTag = "PCB", transformer = SimpleComponentTransformer.class)
|
||||
public class SolderPad extends AbstractComponent<Void> {
|
||||
@@ -76,6 +73,10 @@ public class SolderPad extends AbstractComponent<Void> {
|
||||
drawingObserver.startTrackingContinuityArea(true);
|
||||
if (type == Type.ROUND) {
|
||||
g2d.fill(new Ellipse2D.Double(point.x - diameter / 2, point.y - diameter / 2, diameter, diameter));
|
||||
} else if (type == Type.OVAL_HORIZONTAL) {
|
||||
g2d.fill(new Ellipse2D.Double(point.x - diameter / 2, point.y - diameter * 3 / 8, diameter, diameter * 3 / 4));
|
||||
} else if (type == Type.OVAL_VERTICAL) {
|
||||
g2d.fill(new Ellipse2D.Double(point.x - diameter * 3 / 8, point.y - diameter / 2, diameter * 3 / 4, diameter));
|
||||
} else {
|
||||
g2d.fill(new Rectangle2D.Double(point.x - diameter / 2, point.y - diameter / 2, diameter, diameter));
|
||||
}
|
||||
@@ -96,7 +97,7 @@ public class SolderPad extends AbstractComponent<Void> {
|
||||
g2d.fillOval((width - holeDiameter) / 2, (height - holeDiameter) / 2, holeDiameter, holeDiameter);
|
||||
}
|
||||
|
||||
@EditableProperty(validatorClass = PositiveMeasureValidator.class)
|
||||
@EditableProperty(validatorClass = PositiveNonZeroMeasureValidator.class)
|
||||
public Size getSize() {
|
||||
return size;
|
||||
}
|
||||
@@ -105,7 +106,7 @@ public class SolderPad extends AbstractComponent<Void> {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Hole")
|
||||
@EditableProperty(name = "Hole", validatorClass = PositiveMeasureValidator.class)
|
||||
public Size getHoleSize() {
|
||||
if (holeSize == null) {
|
||||
holeSize = HOLE_SIZE;
|
||||
@@ -182,15 +183,20 @@ public class SolderPad extends AbstractComponent<Void> {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getControlPointNodeName(int index) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(Void value) {}
|
||||
|
||||
public static enum Type {
|
||||
ROUND, SQUARE;
|
||||
ROUND, SQUARE, OVAL_HORIZONTAL, OVAL_VERTICAL;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name().substring(0, 1) + name().substring(1).toLowerCase();
|
||||
return name().substring(0, 1) + name().substring(1).toLowerCase().replace('_', ' ');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Point;
|
||||
|
||||
import org.diylc.common.ObjectCache;
|
||||
import org.diylc.common.SimpleComponentTransformer;
|
||||
import org.diylc.components.AbstractComponent;
|
||||
import org.diylc.components.boards.AbstractBoard;
|
||||
@@ -43,7 +44,7 @@ import org.diylc.utils.Constants;
|
||||
|
||||
@ComponentDescriptor(name = "Trace Cut", category = "Connectivity", author = "Branislav Stojkovic",
|
||||
description = "Designates the place where a trace on the vero board needs to be cut", instanceNamePrefix = "Cut",
|
||||
stretchable = false, zOrder = IDIYComponent.BOARD + 1, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false,
|
||||
zOrder = IDIYComponent.BOARD + 1, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false,
|
||||
transformer = SimpleComponentTransformer.class)
|
||||
public class TraceCut extends AbstractComponent<Void> {
|
||||
|
||||
@@ -72,6 +73,7 @@ public class TraceCut extends AbstractComponent<Void> {
|
||||
if (checkPointsClipped(g2d.getClip())) {
|
||||
return;
|
||||
}
|
||||
g2d.setStroke(ObjectCache.getInstance().fetchZoomableStroke(1f));
|
||||
int size = getClosestOdd((int) this.size.convertToPixels());
|
||||
int cutWidth = getClosestOdd((int) CUT_WIDTH.convertToPixels());
|
||||
if (getCutBetweenHoles()) {
|
||||
@@ -231,4 +233,9 @@ public class TraceCut extends AbstractComponent<Void> {
|
||||
public String getName() {
|
||||
return super.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getControlPointNodeName(int index) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Point;
|
||||
|
||||
import org.diylc.common.ObjectCache;
|
||||
import org.diylc.common.SimpleComponentTransformer;
|
||||
import org.diylc.components.AbstractComponent;
|
||||
import org.diylc.core.ComponentState;
|
||||
@@ -41,7 +42,7 @@ import org.diylc.core.measures.SizeUnit;
|
||||
import org.diylc.utils.Constants;
|
||||
|
||||
@ComponentDescriptor(name = "Turret Lug", category = "Connectivity", author = "Branislav Stojkovic",
|
||||
description = "Turret terminal lug", instanceNamePrefix = "Eyelet", stretchable = false,
|
||||
description = "Turret terminal lug", instanceNamePrefix = "Turret",
|
||||
zOrder = IDIYComponent.TRACE + 0.1, bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, autoEdit = false,
|
||||
keywordPolicy = KeywordPolicy.SHOW_TYPE_NAME, transformer = SimpleComponentTransformer.class)
|
||||
public class Turret extends AbstractComponent<String> {
|
||||
@@ -67,6 +68,7 @@ public class Turret extends AbstractComponent<String> {
|
||||
int diameter = getClosestOdd((int) size.convertToPixels());
|
||||
int holeDiameter = getClosestOdd((int) holeSize.convertToPixels());
|
||||
g2d.setColor(color);
|
||||
g2d.setStroke(ObjectCache.getInstance().fetchZoomableStroke(1f));
|
||||
drawingObserver.startTrackingContinuityArea(true);
|
||||
g2d.fillOval(point.x - diameter / 2, point.y - diameter / 2, diameter, diameter);
|
||||
drawingObserver.stopTrackingContinuityArea();
|
||||
@@ -161,4 +163,9 @@ public class Turret extends AbstractComponent<String> {
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getControlPointNodeName(int index) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,441 @@
|
||||
/*
|
||||
*
|
||||
* DIY Layout Creator (DIYLC). Copyright (c) 2009-2018 held jointly by the individual authors.
|
||||
*
|
||||
* This file is part of DIYLC.
|
||||
*
|
||||
* DIYLC is free software: you can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* DIYLC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with DIYLC. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.diylc.components.connectivity;
|
||||
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Point;
|
||||
import java.awt.Stroke;
|
||||
import java.awt.geom.Area;
|
||||
import java.awt.geom.CubicCurve2D;
|
||||
import java.awt.geom.Line2D;
|
||||
import java.awt.geom.Path2D;
|
||||
import java.awt.geom.PathIterator;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.diylc.common.LineStyle;
|
||||
import org.diylc.common.ObjectCache;
|
||||
import org.diylc.common.SimpleComponentTransformer;
|
||||
import org.diylc.components.AbstractCurvedComponent;
|
||||
import org.diylc.core.ComponentState;
|
||||
import org.diylc.core.IContinuity;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.IDrawingObserver;
|
||||
import org.diylc.core.annotations.BomPolicy;
|
||||
import org.diylc.core.annotations.ComponentDescriptor;
|
||||
import org.diylc.core.annotations.EditableProperty;
|
||||
import org.diylc.utils.Constants;
|
||||
|
||||
@ComponentDescriptor(name = "Twisted Leads", author = "Branislav Stojkovic", category = "Connectivity",
|
||||
instanceNamePrefix = "W", description = "A pair of flexible leads twisted tighly together", zOrder = IDIYComponent.COMPONENT,
|
||||
flexibleZOrder = true, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false,
|
||||
transformer = SimpleComponentTransformer.class)
|
||||
public class TwistedWire extends AbstractCurvedComponent<Void> implements IContinuity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static Color COLOR = Color.green;
|
||||
public static Color COLOR2 = Color.blue;
|
||||
public static Color STRIPE_COLOR = Color.yellow;
|
||||
public static Color STRIPE_COLOR2 = Color.decode("#FF00FF");
|
||||
public static double INSULATION_THICKNESS_PCT = 0.3;
|
||||
|
||||
protected AWG gauge = AWG._22;
|
||||
|
||||
private Color color2 = COLOR2;
|
||||
private Color stripeColor = STRIPE_COLOR;
|
||||
private Color stripeColor2 = STRIPE_COLOR2;
|
||||
private boolean stripe1 = false;
|
||||
private boolean stripe2 = false;
|
||||
|
||||
// cached areas
|
||||
transient private Area firstLeadArea = null;
|
||||
transient private Area secondLeadArea = null;
|
||||
|
||||
transient private Area firstLeadStripeArea = null;
|
||||
transient private Area secondLeadStripeArea = null;
|
||||
|
||||
@Override
|
||||
protected Color getDefaultColor() {
|
||||
return COLOR;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawCurve(Path2D curve, Graphics2D g2d, ComponentState componentState, IDrawingObserver drawingObserver) {
|
||||
int thickness = (int) (gauge.diameterIn() * Constants.PIXELS_PER_INCH * (1 + 2 * INSULATION_THICKNESS_PCT)) - 1;
|
||||
Color curveColor1 =
|
||||
componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR
|
||||
: color;
|
||||
Color curveColor2 =
|
||||
componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR
|
||||
: color2;
|
||||
|
||||
if (firstLeadArea == null || secondLeadArea == null) {
|
||||
firstLeadArea = new Area();
|
||||
secondLeadArea = new Area();
|
||||
recalculate(curve, thickness, firstLeadArea, secondLeadArea, false);
|
||||
|
||||
if (stripe1 || stripe2) {
|
||||
firstLeadStripeArea = new Area();
|
||||
secondLeadStripeArea = new Area();
|
||||
recalculate(curve, thickness, firstLeadStripeArea, secondLeadStripeArea, true);
|
||||
firstLeadStripeArea.intersect(firstLeadArea);
|
||||
secondLeadStripeArea.intersect(secondLeadArea);
|
||||
}
|
||||
}
|
||||
|
||||
g2d.setColor(curveColor1);
|
||||
g2d.fill(firstLeadArea);
|
||||
|
||||
if (stripe1 && componentState == ComponentState.NORMAL) {
|
||||
drawingObserver.stopTracking();
|
||||
g2d.setColor(stripeColor);
|
||||
g2d.fill(firstLeadStripeArea);
|
||||
drawingObserver.startTracking();
|
||||
}
|
||||
|
||||
g2d.setColor(curveColor2);
|
||||
g2d.fill(secondLeadArea);
|
||||
|
||||
if (stripe2 && componentState == ComponentState.NORMAL) {
|
||||
drawingObserver.stopTracking();
|
||||
g2d.setColor(stripeColor2);
|
||||
g2d.fill(secondLeadStripeArea);
|
||||
drawingObserver.startTracking();
|
||||
}
|
||||
|
||||
if (componentState == ComponentState.NORMAL) {
|
||||
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1f));
|
||||
g2d.setColor(color.darker());
|
||||
g2d.draw(firstLeadArea);
|
||||
g2d.setColor(color2.darker());
|
||||
g2d.draw(secondLeadArea);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawIcon(Graphics2D g2d, int width, int height) {
|
||||
Stroke stroke = ObjectCache.getInstance().fetchBasicStroke(3);
|
||||
CubicCurve2D curve1 = new CubicCurve2D.Double(2, height - 2, width - 4, height - 4, 4, 4, width - 2, 2);
|
||||
CubicCurve2D curve2 = new CubicCurve2D.Double(2, height - 2, 4, 4, width - 4, height - 4, width - 2, 2);
|
||||
|
||||
Area area1 = new Area(stroke.createStrokedShape(curve1));
|
||||
Area area2 = new Area(stroke.createStrokedShape(curve2));
|
||||
area2.subtract(area1);
|
||||
|
||||
g2d.setColor(COLOR2);
|
||||
g2d.fill(area2);
|
||||
g2d.setColor(COLOR);
|
||||
g2d.fill(area1);
|
||||
|
||||
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1));
|
||||
g2d.setColor(COLOR2.darker());
|
||||
g2d.draw(area2);
|
||||
g2d.setColor(COLOR.darker());
|
||||
g2d.draw(area1);
|
||||
}
|
||||
|
||||
@EditableProperty(name = "AWG")
|
||||
public AWG getGauge() {
|
||||
return gauge;
|
||||
}
|
||||
|
||||
public void setGauge(AWG gauge) {
|
||||
this.gauge = gauge;
|
||||
|
||||
// invalidate cached areas
|
||||
this.firstLeadArea = null;
|
||||
this.secondLeadArea = null;
|
||||
this.firstLeadStripeArea = null;
|
||||
this.secondLeadStripeArea = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setControlPoint(Point point, int index) {
|
||||
super.setControlPoint(point, index);
|
||||
|
||||
// invalidate cached areas
|
||||
this.firstLeadArea = null;
|
||||
this.secondLeadArea = null;
|
||||
this.firstLeadStripeArea = null;
|
||||
this.secondLeadStripeArea = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPointCount(PointCount pointCount) {
|
||||
super.setPointCount(pointCount);
|
||||
|
||||
// invalidate cached areas
|
||||
this.firstLeadArea = null;
|
||||
this.secondLeadArea = null;
|
||||
this.firstLeadStripeArea = null;
|
||||
this.secondLeadStripeArea = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void getValue() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(Void value) {}
|
||||
|
||||
@EditableProperty(name = "Color 1")
|
||||
public Color getLeadColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Color 2")
|
||||
public Color getColor2() {
|
||||
return color2;
|
||||
}
|
||||
|
||||
public void setColor2(Color color2) {
|
||||
this.color2 = color2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LineStyle getStyle() {
|
||||
// prevent from editing
|
||||
return super.getStyle();
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Stripe Color 1")
|
||||
public Color getStripeColor() {
|
||||
return stripeColor;
|
||||
}
|
||||
|
||||
public void setStripeColor(Color stripeColor) {
|
||||
this.stripeColor = stripeColor;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Stripe Color 2")
|
||||
public Color getStripeColor2() {
|
||||
return stripeColor2;
|
||||
}
|
||||
|
||||
public void setStripeColor2(Color stripeColor2) {
|
||||
this.stripeColor2 = stripeColor2;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Stripe 1")
|
||||
public boolean getStripe1() {
|
||||
return stripe1;
|
||||
}
|
||||
|
||||
public void setStripe1(boolean stripe1) {
|
||||
this.stripe1 = stripe1;
|
||||
|
||||
if (stripe1) {
|
||||
// invalidate cached areas
|
||||
this.firstLeadArea = null;
|
||||
this.secondLeadArea = null;
|
||||
this.firstLeadStripeArea = null;
|
||||
this.secondLeadStripeArea = null;
|
||||
}
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Stripe 2")
|
||||
public boolean getStripe2() {
|
||||
return stripe2;
|
||||
}
|
||||
|
||||
public void setStripe2(boolean stripe2) {
|
||||
this.stripe2 = stripe2;
|
||||
|
||||
if (stripe2) {
|
||||
// invalidate cached areas
|
||||
this.firstLeadArea = null;
|
||||
this.secondLeadArea = null;
|
||||
this.firstLeadStripeArea = null;
|
||||
this.secondLeadStripeArea = null;
|
||||
}
|
||||
}
|
||||
|
||||
// hard-core math below :)
|
||||
|
||||
public void recalculate(Path2D path, float thickness, Area firstLeadArea, Area secondLeadArea, boolean stripe) {
|
||||
PathIterator iterator = path.getPathIterator(null);
|
||||
float[] coords = new float[6];
|
||||
Point current = new Point();
|
||||
|
||||
// convert all segments to cubic curves
|
||||
List<CubicCurve2D> curves = new ArrayList<CubicCurve2D>();
|
||||
while (!iterator.isDone()) {
|
||||
int type = iterator.currentSegment(coords);
|
||||
switch (type) {
|
||||
case PathIterator.SEG_MOVETO:
|
||||
current.setLocation(coords[0], coords[1]);
|
||||
break;
|
||||
case PathIterator.SEG_LINETO:
|
||||
curves.add(new CubicCurve2D.Double(current.x, current.y, (current.x + coords[0]) / 2,
|
||||
(current.y + coords[1]) / 2, (current.x + coords[0]) / 2, (current.y + coords[1]) / 2, coords[0],
|
||||
coords[1]));
|
||||
current.setLocation(coords[0], coords[1]);
|
||||
break;
|
||||
case PathIterator.SEG_QUADTO:
|
||||
curves.add(new CubicCurve2D.Double(current.x, current.y, coords[0], coords[1], coords[0], coords[1],
|
||||
coords[2], coords[3]));
|
||||
current.setLocation(coords[2], coords[3]);
|
||||
break;
|
||||
case PathIterator.SEG_CUBICTO:
|
||||
curves.add(new CubicCurve2D.Double(current.x, current.y, coords[0], coords[1], coords[2], coords[3],
|
||||
coords[4], coords[5]));
|
||||
current.setLocation(coords[4], coords[5]);
|
||||
break;
|
||||
}
|
||||
iterator.next();
|
||||
}
|
||||
|
||||
Stroke stroke;
|
||||
|
||||
if (stripe)
|
||||
stroke = ObjectCache.getInstance().fetchStroke(thickness, new float[] { thickness / 2, thickness * 2 }, thickness * 10, BasicStroke.CAP_BUTT);
|
||||
else
|
||||
stroke = ObjectCache.getInstance().fetchBasicStroke(thickness);
|
||||
|
||||
double segmentLength = thickness * 6;
|
||||
|
||||
// Convert to polygon
|
||||
List<Line2D> polygon = new ArrayList<Line2D>();
|
||||
for (CubicCurve2D curve : curves)
|
||||
polygon.addAll(split(curve, segmentLength));
|
||||
|
||||
List<Path2D> firstCurves = new ArrayList<Path2D>();
|
||||
List<Path2D> secondCurves = new ArrayList<Path2D>();
|
||||
|
||||
Path2D current1 = new Path2D.Double();
|
||||
Path2D current2 = new Path2D.Double();
|
||||
double offset = thickness * 1.5;
|
||||
double rectSize = thickness * 3.5;
|
||||
|
||||
current1.moveTo(polygon.get(0).getX1(), polygon.get(0).getY1());
|
||||
current2.moveTo(polygon.get(0).getX1(), polygon.get(0).getY1());
|
||||
|
||||
// create curved paths for each segment of the twisted pair
|
||||
for (int i = 0; i < polygon.size(); i++) {
|
||||
Line2D line = polygon.get(i);
|
||||
double centerX = (line.getX1() + line.getX2()) / 2;
|
||||
double centerY = (line.getY1() + line.getY2()) / 2;
|
||||
double theta = Math.atan2(line.getY2() - line.getY1(), line.getX2() - line.getX1());
|
||||
|
||||
double sign = i % 2 == 0 ? 1 : -1;
|
||||
|
||||
double theta1 = theta - sign * Math.PI / 2;
|
||||
double theta2 = theta + sign * Math.PI / 2;
|
||||
|
||||
current1.quadTo(centerX + offset * Math.cos(theta1),
|
||||
centerY + offset * Math.sin(theta1), line.getX2(), line.getY2());
|
||||
current2.quadTo(centerX + offset * Math.cos(theta2),
|
||||
centerY + offset * Math.sin(theta2), line.getX2(), line.getY2());
|
||||
|
||||
if (i % 2 == 0 || i == polygon.size() - 1) {
|
||||
firstCurves.add(current1);
|
||||
current1 = new Path2D.Double();
|
||||
current1.moveTo(line.getX2(), line.getY2());
|
||||
}
|
||||
if (i % 2 == 1 || i == polygon.size() - 1) {
|
||||
secondCurves.add(current2);
|
||||
current2 = new Path2D.Double();
|
||||
current2.moveTo(line.getX2(), line.getY2());
|
||||
}
|
||||
}
|
||||
|
||||
// convert to Area
|
||||
for (Path2D p : firstCurves) {
|
||||
firstLeadArea.add(new Area(stroke.createStrokedShape(p)));
|
||||
}
|
||||
for (Path2D p : secondCurves) {
|
||||
secondLeadArea.add(new Area(stroke.createStrokedShape(p)));
|
||||
}
|
||||
|
||||
// at overlapping points, decide which lead goes on top and clear the overlapping area from the lead below
|
||||
for (int i = 0; i < polygon.size(); i++) {
|
||||
Line2D line = polygon.get(i);
|
||||
Area pointRect1 = new Area(new Rectangle2D.Double(line.getX1() - rectSize / 2, line.getY1() - rectSize / 2, rectSize, rectSize));
|
||||
|
||||
if (i % 2 == 1) {
|
||||
pointRect1.intersect(firstLeadArea);
|
||||
secondLeadArea.subtract(pointRect1);
|
||||
} else {
|
||||
pointRect1.intersect(secondLeadArea);
|
||||
firstLeadArea.subtract(pointRect1);
|
||||
}
|
||||
|
||||
if (i == polygon.size() - 1) {
|
||||
Area pointRect2 = new Area(new Rectangle2D.Double(line.getX2() - rectSize / 2, line.getY2() - rectSize / 2, rectSize, rectSize));
|
||||
if (i % 2 == 0) {
|
||||
pointRect2.intersect(firstLeadArea);
|
||||
secondLeadArea.subtract(pointRect2);
|
||||
} else {
|
||||
pointRect2.intersect(secondLeadArea);
|
||||
firstLeadArea.subtract(pointRect2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// splits a curve into a series of lines
|
||||
private List<Line2D> split(CubicCurve2D curve, double segmentLength) {
|
||||
Point2D p1 = curve.getP1();
|
||||
Point2D p2 = curve.getP2();
|
||||
List<Line2D> res = new ArrayList<Line2D>();
|
||||
|
||||
double length = Double.MAX_VALUE;
|
||||
|
||||
if (p1.distance(p2) <= segmentLength)
|
||||
length = calculateLength(curve, segmentLength / 10);
|
||||
|
||||
if (length <= segmentLength) {
|
||||
res.add(new Line2D.Double(p1, p2));
|
||||
} else {
|
||||
CubicCurve2D left = new CubicCurve2D.Double();
|
||||
CubicCurve2D right = new CubicCurve2D.Double();
|
||||
curve.subdivide(left, right);
|
||||
res.addAll(split(left, segmentLength));
|
||||
res.addAll(split(right, segmentLength));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// calculates length of a curve, given the precision
|
||||
private double calculateLength(CubicCurve2D curve, double precision) {
|
||||
Point2D p1 = curve.getP1();
|
||||
Point2D p2 = curve.getP2();
|
||||
|
||||
double d = p1.distance(p2);
|
||||
if (d <= precision) {
|
||||
return d;
|
||||
}
|
||||
|
||||
CubicCurve2D left = new CubicCurve2D.Double();
|
||||
CubicCurve2D right = new CubicCurve2D.Double();
|
||||
curve.subdivide(left, right);
|
||||
|
||||
return calculateLength(left, precision) + calculateLength(right, precision);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean arePointsConnected(int index1, int index2) {
|
||||
return Math.abs(index1 - index2) == getControlPointCount() - 1;
|
||||
}
|
||||
}
|
||||
@@ -51,8 +51,8 @@ import org.diylc.core.measures.Size;
|
||||
import org.diylc.core.measures.SizeUnit;
|
||||
import org.diylc.utils.Constants;
|
||||
|
||||
@ComponentDescriptor(name = "9V Battery Snap", category = "Electromechanical", author = "Branislav Stojkovic",
|
||||
description = "", stretchable = false, zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "BTR",
|
||||
@ComponentDescriptor(name = "9V Battery Snap", category = "Electro-Mechanical", author = "Branislav Stojkovic",
|
||||
description = "", zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "BTR",
|
||||
autoEdit = false, transformer = BatterySnapTransformer.class)
|
||||
public class BatterySnap9V extends AbstractTransparentComponent<String> {
|
||||
|
||||
|
||||
@@ -34,12 +34,13 @@ import java.awt.geom.Ellipse2D;
|
||||
import java.awt.geom.RoundRectangle2D;
|
||||
|
||||
import org.diylc.appframework.miscutils.ConfigurationManager;
|
||||
import org.diylc.awt.StringUtils;
|
||||
import org.diylc.common.HorizontalAlignment;
|
||||
import org.diylc.common.IPlugInPort;
|
||||
import org.diylc.common.ObjectCache;
|
||||
import org.diylc.common.Orientation;
|
||||
import org.diylc.common.VerticalAlignment;
|
||||
import org.diylc.components.AbstractTransparentComponent;
|
||||
import org.diylc.components.AbstractMultiPartComponent;
|
||||
import org.diylc.components.transform.CliffJackTransformer;
|
||||
import org.diylc.core.ComponentState;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
@@ -53,10 +54,10 @@ import org.diylc.core.measures.Size;
|
||||
import org.diylc.core.measures.SizeUnit;
|
||||
import org.diylc.utils.Constants;
|
||||
|
||||
@ComponentDescriptor(name = "Cliff 1/4\" Jack", category = "Electromechanical", author = "Branislav Stojkovic",
|
||||
description = "Cliff-style closed panel mount 1/4\" phono jack", stretchable = false,
|
||||
@ComponentDescriptor(name = "Cliff 1/4\" Jack", category = "Electro-Mechanical", author = "Branislav Stojkovic",
|
||||
description = "Cliff-style closed panel mount 1/4\" phono jack",
|
||||
zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "J", autoEdit = false, transformer = CliffJackTransformer.class)
|
||||
public class CliffJack1_4 extends AbstractTransparentComponent<String> {
|
||||
public class CliffJack1_4 extends AbstractMultiPartComponent<String> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@@ -74,7 +75,7 @@ public class CliffJack1_4 extends AbstractTransparentComponent<String> {
|
||||
private Point[] controlPoints = new Point[] {new Point(0, 0)};
|
||||
private JackType type = JackType.MONO;
|
||||
private Orientation orientation = Orientation.DEFAULT;
|
||||
transient private Shape[] body;
|
||||
transient private Area[] body;
|
||||
private String value = "";
|
||||
|
||||
public CliffJack1_4() {
|
||||
@@ -129,29 +130,27 @@ public class CliffJack1_4 extends AbstractTransparentComponent<String> {
|
||||
return angle;
|
||||
}
|
||||
|
||||
public Shape[] getBody() {
|
||||
public Area[] getBody() {
|
||||
if (body == null) {
|
||||
body = new Shape[5];
|
||||
body = new Area[5];
|
||||
|
||||
// Create body.
|
||||
int bodyLength = (int) BODY_LENGTH.convertToPixels();
|
||||
int bodyWidth = (int) BODY_WIDTH.convertToPixels();
|
||||
int centerX = (controlPoints[0].x + controlPoints[3].x) / 2;
|
||||
int centerY = (controlPoints[0].y + controlPoints[3].y) / 2;
|
||||
body[0] = new Rectangle(centerX - bodyLength / 2, centerY - bodyWidth / 2, bodyLength, bodyWidth);
|
||||
body[0] = new Area(new Rectangle(centerX - bodyLength / 2, centerY - bodyWidth / 2, bodyLength, bodyWidth));
|
||||
|
||||
int tailLength = (int) TAIL_LENGTH.convertToPixels();
|
||||
body[1] =
|
||||
new RoundRectangle2D.Double(centerX - bodyLength / 2 - tailLength, centerY - bodyWidth / 4, tailLength * 2,
|
||||
bodyWidth / 2, tailLength, tailLength);
|
||||
body[1] = new Area(new RoundRectangle2D.Double(centerX - bodyLength / 2 - tailLength, centerY - bodyWidth / 4, tailLength * 2,
|
||||
bodyWidth / 2, tailLength, tailLength));
|
||||
Area tailArea = new Area(body[1]);
|
||||
tailArea.subtract(new Area(body[0]));
|
||||
body[1] = tailArea;
|
||||
|
||||
body[2] = new Rectangle(centerX + bodyLength / 2, centerY - bodyWidth / 4, tailLength, bodyWidth / 2);
|
||||
body[2] = new Area(new Rectangle(centerX + bodyLength / 2, centerY - bodyWidth / 4, tailLength, bodyWidth / 2));
|
||||
|
||||
body[3] =
|
||||
new Rectangle(centerX + bodyLength / 2 + tailLength, centerY - bodyWidth / 4, tailLength, bodyWidth / 2);
|
||||
body[3] = new Area(new Rectangle(centerX + bodyLength / 2 + tailLength, centerY - bodyWidth / 4, tailLength, bodyWidth / 2));
|
||||
tailArea = new Area(body[3]);
|
||||
int radius = bodyLength / 2 + tailLength * 2;
|
||||
tailArea.intersect(new Area(new Ellipse2D.Double(centerX - radius, centerY - radius, radius * 2, radius * 2)));
|
||||
@@ -197,7 +196,7 @@ public class CliffJack1_4 extends AbstractTransparentComponent<String> {
|
||||
Shape[] body = getBody();
|
||||
|
||||
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1));
|
||||
if (componentState != ComponentState.DRAGGING) {
|
||||
// if (componentState != ComponentState.DRAGGING) {
|
||||
Composite oldComposite = g2d.getComposite();
|
||||
if (alpha < MAX_ALPHA) {
|
||||
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA));
|
||||
@@ -210,18 +209,14 @@ public class CliffJack1_4 extends AbstractTransparentComponent<String> {
|
||||
g2d.fill(body[i]);
|
||||
}
|
||||
g2d.setComposite(oldComposite);
|
||||
}
|
||||
// }
|
||||
|
||||
Color finalBorderColor;
|
||||
Theme theme = (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME);
|
||||
if (outlineMode) {
|
||||
finalBorderColor =
|
||||
componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR
|
||||
: theme.getOutlineColor();
|
||||
finalBorderColor = theme.getOutlineColor();
|
||||
} else {
|
||||
finalBorderColor =
|
||||
componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR
|
||||
: BORDER_COLOR;
|
||||
finalBorderColor = BORDER_COLOR;
|
||||
}
|
||||
|
||||
g2d.setColor(finalBorderColor);
|
||||
@@ -252,7 +247,9 @@ public class CliffJack1_4 extends AbstractTransparentComponent<String> {
|
||||
g2d.setFont(project.getFont());
|
||||
int centerX = (controlPoints[0].x + controlPoints[3].x) / 2;
|
||||
int centerY = (controlPoints[0].y + controlPoints[3].y) / 2;
|
||||
drawCenteredText(g2d, name, centerX, centerY, HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
|
||||
StringUtils.drawCenteredText(g2d, name, centerX, centerY, HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
|
||||
|
||||
drawSelectionOutline(g2d, componentState, outlineMode, project, drawingObserver);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -342,4 +339,9 @@ public class CliffJack1_4 extends AbstractTransparentComponent<String> {
|
||||
this.orientation = orientation;
|
||||
updateControlPoints();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPointMoveFreely(int pointIndex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user