mirror of
https://github.com/bancika/diy-layout-creator
synced 2026-11-13 02:32:09 +10:00
Building blocks (#1072)
* composite block support * naming * Added ability to set node name (or names) for some connectivity components * cleanup * Include building blocks in the Recently Used category * Prompt to confirm the overwrite when saving over the existing building blocks; When saving building blocks, present a drop down list with most recently used building blocks * add alpha to composite * Update CompositeComponentTest.java * cleanup * Update CompositeComponent.java * cleanup * Update CompositeComponent.java * <org.diylc.appframework.update.Change> <changeType>IMPROVEMENT</changeType> <description>When saving building blocks, present a drop down list with most recently used building blocks for quick selection</description> </org.diylc.appframework.update.Change> * Diode components now label their terminal nodes as 'A' (anode) and 'K' (cathode) instead of '1' and '2' * Capacitor components now label their terminal nodes as '+' and '-' instead of '1' and '2' when 'Polarized' property is ticked
This commit is contained in:
+224
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2025 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.composite;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.diylc.common.Percentage;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.netlist.Node;
|
||||
import org.diylc.serialization.ProjectFileManager;
|
||||
import org.diylc.testcomponents.TwoPointTestComponent;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Exercises the delegation, rigidity, cloning and equality behavior described in
|
||||
* {@code docs/plans/composite-building-blocks.md}.
|
||||
*/
|
||||
public class CompositeComponentTest {
|
||||
|
||||
private CompositeComponent twoChildComposite() {
|
||||
CompositeComponent composite = new CompositeComponent();
|
||||
composite.setName("BLK1");
|
||||
composite.initBlockName("Test Block");
|
||||
composite.getChildComponents().add(new TwoPointTestComponent("R1",
|
||||
new Point2D.Double(0, 0), new Point2D.Double(10, 0)));
|
||||
composite.getChildComponents().add(new TwoPointTestComponent("R2",
|
||||
new Point2D.Double(20, 0), new Point2D.Double(30, 0)));
|
||||
return composite;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void controlPointCountIsSumOverChildren() {
|
||||
CompositeComponent composite = twoChildComposite();
|
||||
assertEquals(4, composite.getControlPointCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void controlPointsMapToTheRightChildAndLocalIndex() {
|
||||
CompositeComponent composite = twoChildComposite();
|
||||
|
||||
assertEquals(new Point2D.Double(0, 0), composite.getControlPoint(0));
|
||||
assertEquals(new Point2D.Double(10, 0), composite.getControlPoint(1));
|
||||
assertEquals(new Point2D.Double(20, 0), composite.getControlPoint(2));
|
||||
assertEquals(new Point2D.Double(30, 0), composite.getControlPoint(3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setControlPointDelegatesToTheOwningChild() {
|
||||
CompositeComponent composite = twoChildComposite();
|
||||
|
||||
composite.setControlPoint(new Point2D.Double(99, 99), 2);
|
||||
|
||||
assertEquals(new Point2D.Double(99, 99), composite.getControlPoint(2));
|
||||
// the sibling child's points must be untouched
|
||||
assertEquals(new Point2D.Double(30, 0), composite.getControlPoint(3));
|
||||
TwoPointTestComponent r2 = (TwoPointTestComponent) composite.getChildComponents().get(1);
|
||||
assertEquals(new Point2D.Double(99, 99), r2.getControlPoint(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stickinessIsDelegatedPerChildPoint() {
|
||||
CompositeComponent composite = twoChildComposite();
|
||||
((TwoPointTestComponent) composite.getChildComponents().get(0)).setSticky(1, false);
|
||||
|
||||
assertTrue(composite.isControlPointSticky(0));
|
||||
assertFalse(composite.isControlPointSticky(1));
|
||||
assertTrue(composite.isControlPointSticky(2));
|
||||
assertTrue(composite.isControlPointSticky(3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isAlwaysRigid() {
|
||||
CompositeComponent composite = twoChildComposite();
|
||||
for (int i = 0; i < composite.getControlPointCount(); i++)
|
||||
assertFalse("point " + i + " should not move freely", composite.canPointMoveFreely(i));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nodeNamingProducesHierarchicalNetlistLabels() {
|
||||
// Design decision D3: Node.toString() should read "<composite>.<child>.<local point name>"
|
||||
CompositeComponent composite = twoChildComposite();
|
||||
|
||||
Node r1FirstPoint = new Node(composite, 0);
|
||||
Node r2FirstPoint = new Node(composite, 2);
|
||||
Node r2SecondPoint = new Node(composite, 3);
|
||||
|
||||
assertEquals("BLK1.1", r1FirstPoint.toString());
|
||||
assertEquals("BLK1.1", r2FirstPoint.toString());
|
||||
// local point index must reset per child, not keep growing with the flat composite index
|
||||
assertEquals("BLK1.2", r2SecondPoint.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cloneDeepCopiesChildrenSoInstancesAreIndependent() throws Exception {
|
||||
CompositeComponent original = twoChildComposite();
|
||||
|
||||
IDIYComponent<?> clone = original.clone();
|
||||
|
||||
((CompositeComponent) clone).setControlPoint(new Point2D.Double(-1, -1), 0);
|
||||
|
||||
assertEquals(new Point2D.Double(0, 0), original.getControlPoint(0));
|
||||
assertEquals(new Point2D.Double(-1, -1), clone.getControlPoint(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cloneKeepsBothItsOwnAndChildrenIds() throws Exception {
|
||||
// Matches AbstractComponent.clone()'s contract of preserving identity by default - a caller
|
||||
// that needs a genuinely new component (e.g. BuildingBlockManager placing a fresh instance)
|
||||
// reassigns ids itself, exactly as it does for any other component's clone().
|
||||
CompositeComponent original = twoChildComposite();
|
||||
UUID originalChildId = original.getChildComponents().get(0).getId();
|
||||
|
||||
CompositeComponent clone = (CompositeComponent) original.clone();
|
||||
|
||||
assertEquals(original.getId(), clone.getId());
|
||||
assertEquals(originalChildId, clone.getChildComponents().get(0).getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equalsToComparesStructureNotObjectIdentity() throws Exception {
|
||||
CompositeComponent original = twoChildComposite();
|
||||
CompositeComponent clone = (CompositeComponent) original.clone();
|
||||
|
||||
// structurally identical, distinct child objects - must still compare equal
|
||||
assertTrue(original.equalsTo(clone));
|
||||
|
||||
clone.setControlPoint(new Point2D.Double(-1, -1), 0);
|
||||
assertFalse(original.equalsTo(clone));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equalsToRejectsDifferentBlockName() {
|
||||
CompositeComponent a = twoChildComposite();
|
||||
CompositeComponent b = twoChildComposite();
|
||||
b.initBlockName("Different Block");
|
||||
|
||||
assertFalse(a.equalsTo(b));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultsToFullyOpaque() {
|
||||
assertEquals(new Percentage(100), twoChildComposite().getAlpha());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cloneCopiesAlpha() throws Exception {
|
||||
CompositeComponent original = twoChildComposite();
|
||||
original.setAlpha(new Percentage(40));
|
||||
|
||||
CompositeComponent clone = (CompositeComponent) original.clone();
|
||||
|
||||
assertEquals(new Percentage(40), clone.getAlpha());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equalsToRejectsDifferentAlpha() throws Exception {
|
||||
CompositeComponent original = twoChildComposite();
|
||||
CompositeComponent clone = (CompositeComponent) original.clone();
|
||||
assertTrue(original.equalsTo(clone));
|
||||
|
||||
clone.setAlpha(new Percentage(50));
|
||||
assertFalse(original.equalsTo(clone));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void survivesAnXStreamRoundTripAndRebuildsItsIndexLazily() {
|
||||
CompositeComponent original = twoChildComposite();
|
||||
|
||||
String xml = ProjectFileManager.xStreamSerializer.toXML(original);
|
||||
CompositeComponent reloaded = (CompositeComponent) ProjectFileManager.xStreamSerializer.fromXML(xml);
|
||||
|
||||
// the transient child-index arrays are never serialized - this call exercises the lazy
|
||||
// rebuild in buildIndexIfNeeded() on an instance XStream constructed without going through
|
||||
// the no-arg constructor
|
||||
assertEquals(original.getControlPointCount(), reloaded.getControlPointCount());
|
||||
assertEquals(original.getName(), reloaded.getName());
|
||||
assertEquals(original.getBlockName(), reloaded.getBlockName());
|
||||
for (int i = 0; i < original.getControlPointCount(); i++)
|
||||
assertEquals(original.getControlPoint(i), reloaded.getControlPoint(i));
|
||||
assertEquals("BLK1.2", new Node(reloaded, 3).toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void drawIconDoesNotTouchChildren() {
|
||||
// ComponentProcessor draws the palette icon on a default-constructed, childless instance
|
||||
CompositeComponent blank = new CompositeComponent();
|
||||
BufferedImage image = new BufferedImage(32, 32, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D g2d = image.createGraphics();
|
||||
|
||||
blank.drawIcon(g2d, 32, 32);
|
||||
|
||||
g2d.dispose();
|
||||
// no exception means components list (empty) was never dereferenced as if populated
|
||||
assertNotNull(blank.getChildComponents());
|
||||
assertTrue(blank.getChildComponents().isEmpty());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2025 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 static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.awt.geom.Point2D;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.diylc.appframework.miscutils.IConfigurationManager;
|
||||
import org.diylc.common.BlockInstantiationMode;
|
||||
import org.diylc.common.IBlockProcessor;
|
||||
import org.diylc.common.IBlockProcessor.InvalidBlockException;
|
||||
import org.diylc.common.IPlugInPort;
|
||||
import org.diylc.components.composite.CompositeComponent;
|
||||
import org.diylc.core.ISwitch;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.testcomponents.SwitchTestComponent;
|
||||
import org.diylc.testcomponents.TwoPointTestComponent;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Exercises {@link BuildingBlockManager#loadBlock} in both {@link BlockInstantiationMode}s (see
|
||||
* design decision D10 and section 4.4 of {@code docs/plans/composite-building-blocks.md}).
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public class BuildingBlockManagerTest {
|
||||
|
||||
private static final String BLOCK_NAME = "TestBlock";
|
||||
|
||||
private IConfigurationManager<?> configManager;
|
||||
private BuildingBlockManager manager;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
List<IDIYComponent<?>> storedComponents = Arrays.asList(
|
||||
new TwoPointTestComponent("R1", new Point2D.Double(0, 0), new Point2D.Double(10, 0)),
|
||||
new TwoPointTestComponent("R2", new Point2D.Double(20, 0), new Point2D.Double(30, 0)));
|
||||
Map<String, List<IDIYComponent<?>>> blocksMap = new HashMap<String, List<IDIYComponent<?>>>();
|
||||
blocksMap.put(BLOCK_NAME, storedComponents);
|
||||
|
||||
configManager = mock(IConfigurationManager.class);
|
||||
when(configManager.readObject(eq(IPlugInPort.BLOCKS_KEY), org.mockito.ArgumentMatchers.any()))
|
||||
.thenReturn(blocksMap);
|
||||
|
||||
manager = new BuildingBlockManager(configManager, null, new InstantiationManager());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void groupModeClonesEachComponentWithAFreshNameAndId() throws InvalidBlockException {
|
||||
List<IDIYComponent<?>> result =
|
||||
manager.loadBlock(BLOCK_NAME, new ArrayList<IDIYComponent<?>>(), BlockInstantiationMode.GROUP);
|
||||
|
||||
assertEquals(2, result.size());
|
||||
// group mode always assigns fresh, project-unique names (pre-existing behavior, unchanged)
|
||||
assertEquals("TP1", result.get(0).getName());
|
||||
assertEquals("TP2", result.get(1).getName());
|
||||
assertNotEquals(result.get(0).getId(), result.get(1).getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compositeModeWrapsChildrenInASingleComponent() throws InvalidBlockException {
|
||||
List<IDIYComponent<?>> result =
|
||||
manager.loadBlock(BLOCK_NAME, new ArrayList<IDIYComponent<?>>(), BlockInstantiationMode.COMPOSITE);
|
||||
|
||||
assertEquals(1, result.size());
|
||||
assertTrue(result.get(0) instanceof CompositeComponent);
|
||||
CompositeComponent composite = (CompositeComponent) result.get(0);
|
||||
|
||||
assertEquals(BLOCK_NAME, composite.getBlockName());
|
||||
assertEquals("BLK1", composite.getName());
|
||||
assertEquals(4, composite.getControlPointCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compositeModePreservesChildNamesUnlikeGroupMode() throws InvalidBlockException {
|
||||
List<IDIYComponent<?>> result =
|
||||
manager.loadBlock(BLOCK_NAME, new ArrayList<IDIYComponent<?>>(), BlockInstantiationMode.COMPOSITE);
|
||||
CompositeComponent composite = (CompositeComponent) result.get(0);
|
||||
|
||||
// children are namespaced under the composite's own name in the netlist, so their saved
|
||||
// names must survive untouched
|
||||
assertEquals("R1", composite.getChildComponents().get(0).getName());
|
||||
assertEquals("R2", composite.getChildComponents().get(1).getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compositeModeGivesEachInstanceItsOwnNameButChildrenStayIdenticallyNamed()
|
||||
throws InvalidBlockException {
|
||||
List<IDIYComponent<?>> existing = new ArrayList<IDIYComponent<?>>();
|
||||
CompositeComponent first = (CompositeComponent) manager
|
||||
.loadBlock(BLOCK_NAME, existing, BlockInstantiationMode.COMPOSITE).get(0);
|
||||
existing.add(first);
|
||||
|
||||
CompositeComponent second = (CompositeComponent) manager
|
||||
.loadBlock(BLOCK_NAME, existing, BlockInstantiationMode.COMPOSITE).get(0);
|
||||
|
||||
assertNotEquals(first.getName(), second.getName());
|
||||
assertEquals(first.getChildComponents().get(0).getName(), second.getChildComponents().get(0).getName());
|
||||
// but the underlying child components must be distinct objects with distinct ids
|
||||
assertNotEquals(first.getChildComponents().get(0).getId(), second.getChildComponents().get(0).getId());
|
||||
}
|
||||
|
||||
@Test(expected = InvalidBlockException.class)
|
||||
public void groupModeThrowsOnUnknownBlock() throws InvalidBlockException {
|
||||
manager.loadBlock("NoSuchBlock", new ArrayList<IDIYComponent<?>>(), BlockInstantiationMode.GROUP);
|
||||
}
|
||||
|
||||
@Test(expected = InvalidBlockException.class)
|
||||
public void compositeModeThrowsOnUnknownBlock() throws InvalidBlockException {
|
||||
manager.loadBlock("NoSuchBlock", new ArrayList<IDIYComponent<?>>(), BlockInstantiationMode.COMPOSITE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteBlockAlsoStripsItFromTheRecentlyUsedList() {
|
||||
List<String> recent = new ArrayList<String>(Arrays.asList(
|
||||
IBlockProcessor.BLOCK_PREFIX + BLOCK_NAME, "org.diylc.components.SomeComponent"));
|
||||
when(configManager.readObject(eq(IPlugInPort.RECENT_COMPONENTS_KEY),
|
||||
org.mockito.ArgumentMatchers.any())).thenReturn(recent);
|
||||
|
||||
manager.deleteBlock(BLOCK_NAME);
|
||||
|
||||
assertFalse(recent.contains(IBlockProcessor.BLOCK_PREFIX + BLOCK_NAME));
|
||||
assertTrue(recent.contains("org.diylc.components.SomeComponent"));
|
||||
verify(configManager).writeValue(eq(IPlugInPort.RECENT_COMPONENTS_KEY), eq(recent));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compositeModeToleratesAnInternalSwitchWithoutFailing() throws InvalidBlockException {
|
||||
// Design decision D6: the composite is not ISwitch, so a block containing a switch must
|
||||
// still place successfully - it just won't switch (see BuildingBlockManager's log warning).
|
||||
List<IDIYComponent<?>> storedComponents = Arrays.<IDIYComponent<?>>asList(new SwitchTestComponent("SW1"));
|
||||
Map<String, List<IDIYComponent<?>>> blocksMap = new HashMap<String, List<IDIYComponent<?>>>();
|
||||
blocksMap.put("SwitchBlock", storedComponents);
|
||||
when(configManager.readObject(eq(IPlugInPort.BLOCKS_KEY), org.mockito.ArgumentMatchers.any()))
|
||||
.thenReturn(blocksMap);
|
||||
|
||||
List<IDIYComponent<?>> result = manager.loadBlock("SwitchBlock", new ArrayList<IDIYComponent<?>>(),
|
||||
BlockInstantiationMode.COMPOSITE);
|
||||
|
||||
assertNotNull(result);
|
||||
assertEquals(1, result.size());
|
||||
assertTrue(((CompositeComponent) result.get(0)).getChildComponents().get(0) instanceof ISwitch);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2025 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.testcomponents;
|
||||
|
||||
import java.awt.geom.Point2D;
|
||||
|
||||
import org.diylc.core.ISwitch;
|
||||
|
||||
/**
|
||||
* Smallest possible {@link ISwitch} implementation, used to verify that a building block
|
||||
* containing a switch can still be instantiated as a {@code CompositeComponent} (design decision
|
||||
* D6 in {@code docs/plans/composite-building-blocks.md} - the composite itself is not
|
||||
* {@code ISwitch}, so the switch places and draws but contributes no switching behavior).
|
||||
* <p>
|
||||
* Deliberately a public top-level class, not a nested one: {@link
|
||||
* org.diylc.components.AbstractComponent#clone()} instantiates the no-arg constructor via plain
|
||||
* reflection (no {@code setAccessible}), which fails across packages unless both the class and
|
||||
* the constructor are public.
|
||||
*/
|
||||
public class SwitchTestComponent extends TwoPointTestComponent implements ISwitch {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public SwitchTestComponent() {
|
||||
this("SW");
|
||||
}
|
||||
|
||||
public SwitchTestComponent(String name) {
|
||||
super(name, new Point2D.Double(0, 0), new Point2D.Double(10, 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPositionCount() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPositionName(int position) {
|
||||
return position == 0 ? "ON" : "OFF";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean arePointsConnected(int index1, int index2, int position) {
|
||||
return position == 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2025 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.testcomponents;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Point2D;
|
||||
|
||||
import org.diylc.components.AbstractComponent;
|
||||
import org.diylc.core.ComponentState;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.IDrawingObserver;
|
||||
import org.diylc.core.Project;
|
||||
import org.diylc.core.VisibilityPolicy;
|
||||
import org.diylc.core.annotations.ComponentDescriptor;
|
||||
|
||||
/**
|
||||
* Minimal two-point component used to exercise {@code CompositeComponent} and
|
||||
* {@code BuildingBlockManager} in tests: two control points, individually configurable
|
||||
* stickiness, node naming left at the {@link AbstractComponent} default (the 1-based point
|
||||
* index), so a composite's per-child node name delegation can be verified precisely.
|
||||
*/
|
||||
@ComponentDescriptor(name = "Two Point Test", category = "Test", author = "Test",
|
||||
description = "test", instanceNamePrefix = "TP", zOrder = IDIYComponent.COMPONENT)
|
||||
public class TwoPointTestComponent extends AbstractComponent<Void> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Point2D p0;
|
||||
private Point2D p1;
|
||||
private boolean sticky0 = true;
|
||||
private boolean sticky1 = true;
|
||||
|
||||
public TwoPointTestComponent() {
|
||||
this("", new Point2D.Double(0, 0), new Point2D.Double(10, 0));
|
||||
}
|
||||
|
||||
public TwoPointTestComponent(String name, Point2D p0, Point2D p1) {
|
||||
setName(name);
|
||||
this.p0 = p0;
|
||||
this.p1 = p1;
|
||||
}
|
||||
|
||||
public void setSticky(int index, boolean sticky) {
|
||||
if (index == 0)
|
||||
sticky0 = sticky;
|
||||
else
|
||||
sticky1 = sticky;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getControlPointCount() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Point2D getControlPoint(int index) {
|
||||
return index == 0 ? p0 : p1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setControlPoint(Point2D point, int index) {
|
||||
if (index == 0)
|
||||
p0 = point;
|
||||
else
|
||||
p1 = point;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isControlPointSticky(int index) {
|
||||
return index == 0 ? sticky0 : sticky1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VisibilityPolicy getControlPointVisibilityPolicy(int index) {
|
||||
return VisibilityPolicy.ALWAYS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void getValue() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(Void value) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project,
|
||||
IDrawingObserver drawingObserver) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawIcon(Graphics2D g2d, int width, int height) {
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user