mirror of
https://github.com/bancika/diy-layout-creator
synced 2026-11-13 02:32:09 +10:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5dcc3f01d5 | |||
| 7a25a09a16 | |||
| 405309825d | |||
| 6ba947cbfa | |||
| 5a9cc6fff2 | |||
| d7360699c8 | |||
| 465ddbd032 | |||
| efe07e3ee7 | |||
| 66c5ce5ad2 |
@@ -21,7 +21,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.diylc.common;
|
package org.diylc.common;
|
||||||
|
|
||||||
import java.awt.Rectangle;
|
|
||||||
import java.awt.geom.Point2D;
|
import java.awt.geom.Point2D;
|
||||||
|
|
||||||
import org.diylc.core.Project;
|
import org.diylc.core.Project;
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ import org.diylc.core.IDIYComponent;
|
|||||||
import org.diylc.core.Project;
|
import org.diylc.core.Project;
|
||||||
import org.diylc.core.Template;
|
import org.diylc.core.Template;
|
||||||
import org.diylc.core.Theme;
|
import org.diylc.core.Theme;
|
||||||
|
import org.diylc.core.measures.ResizeDimensions;
|
||||||
import org.diylc.core.measures.Size;
|
import org.diylc.core.measures.Size;
|
||||||
import org.diylc.filter.IComponentFilter;
|
import org.diylc.filter.IComponentFilter;
|
||||||
import org.diylc.test.ITestProcessor;
|
import org.diylc.test.ITestProcessor;
|
||||||
@@ -49,9 +50,9 @@ import org.diylc.test.ITestProcessor;
|
|||||||
* Interface for communication between plug-ins and the application. Plug-ins may acquire
|
* Interface for communication between plug-ins and the application. Plug-ins may acquire
|
||||||
* information or make changes through this interface. Application events are dispatched to plug-ins
|
* information or make changes through this interface. Application events are dispatched to plug-ins
|
||||||
* through {@link MessageDispatcher}
|
* through {@link MessageDispatcher}
|
||||||
*
|
*
|
||||||
* @author Branislav Stojkovic
|
* @author Branislav Stojkovic
|
||||||
*
|
*
|
||||||
* @see IPlugIn
|
* @see IPlugIn
|
||||||
* @see MessageDispatcher
|
* @see MessageDispatcher
|
||||||
* @see IMessageListener
|
* @see IMessageListener
|
||||||
@@ -86,18 +87,19 @@ public interface IPlugInPort extends ISelectionProcessor, IMouseProcessor, IKeyP
|
|||||||
public static final String RULER_IN_SUBDIVISION_KEY = "rulerInSubdivision";
|
public static final String RULER_IN_SUBDIVISION_KEY = "rulerInSubdivision";
|
||||||
public static final String CACHING_ENABLED_KEY = "cachingEnabled";
|
public static final String CACHING_ENABLED_KEY = "cachingEnabled";
|
||||||
public static final String FONT_SCALE_FACTOR_KEY = "fontScaleFactor";
|
public static final String FONT_SCALE_FACTOR_KEY = "fontScaleFactor";
|
||||||
|
public static final String SHOW_RESIZE_DIMENSIONS_TOOLTIP_KEY = "showResizeDimensionsTooltip";
|
||||||
|
|
||||||
public static final String RULER_IN_SUBDIVISION_2 = "base of 2";
|
public static final String RULER_IN_SUBDIVISION_2 = "base of 2";
|
||||||
public static final String RULER_IN_SUBDIVISION_10 = "base of 10";
|
public static final String RULER_IN_SUBDIVISION_10 = "base of 10";
|
||||||
public static final String RULER_IN_SUBDIVISION_DEFAULT = RULER_IN_SUBDIVISION_10;
|
public static final String RULER_IN_SUBDIVISION_DEFAULT = RULER_IN_SUBDIVISION_10;
|
||||||
|
|
||||||
public static final String SNAP_TO_NONE = "None";
|
public static final String SNAP_TO_NONE = "None";
|
||||||
public static final String SNAP_TO_GRID = "Grid";
|
public static final String SNAP_TO_GRID = "Grid";
|
||||||
public static final String SNAP_TO_COMPONENTS = "Components";
|
public static final String SNAP_TO_COMPONENTS = "Components";
|
||||||
public static final String SNAP_TO_DEFAULT = SNAP_TO_GRID;
|
public static final String SNAP_TO_DEFAULT = SNAP_TO_GRID;
|
||||||
|
|
||||||
public static final String LOCKED_ALPHA = "lockedAlpha";
|
public static final String LOCKED_ALPHA = "lockedAlpha";
|
||||||
|
|
||||||
public static final String LANGUAGE = "language";
|
public static final String LANGUAGE = "language";
|
||||||
public static final String LANGUAGE_DEFAULT = "English";
|
public static final String LANGUAGE_DEFAULT = "English";
|
||||||
|
|
||||||
@@ -110,25 +112,25 @@ public interface IPlugInPort extends ISelectionProcessor, IMouseProcessor, IKeyP
|
|||||||
public static final int NOBUTTON = 0;
|
public static final int NOBUTTON = 0;
|
||||||
public static final int BUTTON1 = 1;
|
public static final int BUTTON1 = 1;
|
||||||
public static final int BUTTON2 = 2;
|
public static final int BUTTON2 = 2;
|
||||||
public static final int BUTTON3 = 3;
|
public static final int BUTTON3 = 3;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns size of the canvas that takes project dimensions into account as well as zoom level.
|
* Returns size of the canvas that takes project dimensions into account as well as zoom level.
|
||||||
* Each dimension is calculated as the product of the actual size and the number of pixels per
|
* Each dimension is calculated as the product of the actual size and the number of pixels per
|
||||||
* unit. If <code>useZoom</code> is set to true, the result is scaled by zoom factor.
|
* unit. If <code>useZoom</code> is set to true, the result is scaled by zoom factor.
|
||||||
*
|
*
|
||||||
* @param useZoom
|
* @param useZoom
|
||||||
* @param includeExtraSpace
|
* @param includeExtraSpace
|
||||||
*
|
*
|
||||||
* @return canvas dimensions
|
* @return canvas dimensions
|
||||||
*/
|
*/
|
||||||
Dimension getCanvasDimensions(boolean useZoom, boolean includeExtraSpace);
|
Dimension getCanvasDimensions(boolean useZoom, boolean includeExtraSpace);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an instance of {@link Cursor} that should be used at the specified location.
|
* Returns an instance of {@link Cursor} that should be used at the specified location.
|
||||||
*
|
*
|
||||||
* Note: point coordinates are scaled for zoom factor.
|
* Note: point coordinates are scaled for zoom factor.
|
||||||
*
|
*
|
||||||
* @param point
|
* @param point
|
||||||
* @param ctrlDown
|
* @param ctrlDown
|
||||||
* @param shiftDown
|
* @param shiftDown
|
||||||
@@ -139,14 +141,14 @@ public interface IPlugInPort extends ISelectionProcessor, IMouseProcessor, IKeyP
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an instance of currently loaded project.
|
* Returns an instance of currently loaded project.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
Project getCurrentProject();
|
Project getCurrentProject();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads specified {@link Project}.
|
* Loads specified {@link Project}.
|
||||||
*
|
*
|
||||||
* @param project
|
* @param project
|
||||||
* @param freshStart
|
* @param freshStart
|
||||||
* @param filename file name when loading from a file
|
* @param filename file name when loading from a file
|
||||||
@@ -160,22 +162,22 @@ public interface IPlugInPort extends ISelectionProcessor, IMouseProcessor, IKeyP
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads a project from the specified file.
|
* Loads a project from the specified file.
|
||||||
*
|
*
|
||||||
* @param fileName
|
* @param fileName
|
||||||
*/
|
*/
|
||||||
void loadProjectFromFile(String fileName);
|
void loadProjectFromFile(String fileName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves the current project into the specified file.
|
* Saves the current project into the specified file.
|
||||||
*
|
*
|
||||||
* @param fileName
|
* @param fileName
|
||||||
* @param isBackup
|
* @param isBackup
|
||||||
*/
|
*/
|
||||||
void saveProjectToFile(String fileName, boolean isBackup);
|
void saveProjectToFile(String fileName, boolean isBackup);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exports the current project into one or more files - one per layer and potentially drill layer.
|
* Exports the current project into one or more files - one per layer and potentially drill layer.
|
||||||
*
|
*
|
||||||
* @param fileNameBase
|
* @param fileNameBase
|
||||||
* @param g2d
|
* @param g2d
|
||||||
*/
|
*/
|
||||||
@@ -193,7 +195,7 @@ public interface IPlugInPort extends ISelectionProcessor, IMouseProcessor, IKeyP
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows a user dialog if there are changes to confirm that it's safe to proceed.
|
* Shows a user dialog if there are changes to confirm that it's safe to proceed.
|
||||||
*
|
*
|
||||||
* @return true, if file actions (new, open, close) can be taken
|
* @return true, if file actions (new, open, close) can be taken
|
||||||
*/
|
*/
|
||||||
boolean allowFileAction();
|
boolean allowFileAction();
|
||||||
@@ -202,7 +204,7 @@ public interface IPlugInPort extends ISelectionProcessor, IMouseProcessor, IKeyP
|
|||||||
* Returns all available {@link ComponentType}s classified by category. Result is a {@link Map}
|
* Returns all available {@link ComponentType}s classified by category. Result is a {@link Map}
|
||||||
* between category name to a {@link List} of all {@link ComponentType}s that share that category
|
* between category name to a {@link List} of all {@link ComponentType}s that share that category
|
||||||
* name.
|
* name.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
Map<String, List<ComponentType>> getComponentTypes();
|
Map<String, List<ComponentType>> getComponentTypes();
|
||||||
@@ -210,7 +212,7 @@ public interface IPlugInPort extends ISelectionProcessor, IMouseProcessor, IKeyP
|
|||||||
/**
|
/**
|
||||||
* Draws project on the provided {@link Graphics2D}. If the provided filter is not null, it will
|
* Draws project on the provided {@link Graphics2D}. If the provided filter is not null, it will
|
||||||
* be used to filter the components that are shown.
|
* be used to filter the components that are shown.
|
||||||
*
|
*
|
||||||
* @param g2d
|
* @param g2d
|
||||||
* @param drawOptions specific drawing options
|
* @param drawOptions specific drawing options
|
||||||
* @param filter
|
* @param filter
|
||||||
@@ -224,35 +226,35 @@ public interface IPlugInPort extends ISelectionProcessor, IMouseProcessor, IKeyP
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns current zoom level where <code>zoomLevel = 1.0d</code> means 100%.
|
* Returns current zoom level where <code>zoomLevel = 1.0d</code> means 100%.
|
||||||
*
|
*
|
||||||
* @return current zoom level
|
* @return current zoom level
|
||||||
*/
|
*/
|
||||||
double getZoomLevel();
|
double getZoomLevel();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes current zoom level where <code>zoomLevel = 1.0d</code> means 100%
|
* Changes current zoom level where <code>zoomLevel = 1.0d</code> means 100%
|
||||||
*
|
*
|
||||||
* @param zoomLevel new zoom leve
|
* @param zoomLevel new zoom leve
|
||||||
*/
|
*/
|
||||||
void setZoomLevel(double zoomLevel);
|
void setZoomLevel(double zoomLevel);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns current version number.
|
* Returns current version number.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
VersionNumber getCurrentVersionNumber();
|
VersionNumber getCurrentVersionNumber();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns few most recent versions.
|
* Returns few most recent versions.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
List<Version> getRecentUpdates();
|
List<Version> getRecentUpdates();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a list of components to the project.
|
* Adds a list of components to the project.
|
||||||
*
|
*
|
||||||
* @param componentTransferable
|
* @param componentTransferable
|
||||||
* @param autoGroup
|
* @param autoGroup
|
||||||
* @param assignNewNames
|
* @param assignNewNames
|
||||||
@@ -271,7 +273,7 @@ public interface IPlugInPort extends ISelectionProcessor, IMouseProcessor, IKeyP
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets default value for the specified property name for currently selected component types.
|
* Sets default value for the specified property name for currently selected component types.
|
||||||
*
|
*
|
||||||
* @param propertyName display name for property
|
* @param propertyName display name for property
|
||||||
* @param value new default value, must not be null
|
* @param value new default value, must not be null
|
||||||
*/
|
*/
|
||||||
@@ -279,7 +281,7 @@ public interface IPlugInPort extends ISelectionProcessor, IMouseProcessor, IKeyP
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets default value for the specified property name for projects.
|
* Sets default value for the specified property name for projects.
|
||||||
*
|
*
|
||||||
* @param clazz class to set defaults to
|
* @param clazz class to set defaults to
|
||||||
* @param propertyName display name for property
|
* @param propertyName display name for property
|
||||||
* @param value new default value, must not be null
|
* @param value new default value, must not be null
|
||||||
@@ -293,6 +295,15 @@ public interface IPlugInPort extends ISelectionProcessor, IMouseProcessor, IKeyP
|
|||||||
*/
|
*/
|
||||||
List<PropertyWrapper> getMutualSelectionProperties();
|
List<PropertyWrapper> getMutualSelectionProperties();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Available only during resizing, returns the dimensions of the component being resized.
|
||||||
|
* Otherwise returns null.
|
||||||
|
*
|
||||||
|
* @return ResizeDimensions with width, height (in mm or in depending on configuration),
|
||||||
|
* and length (if component implements IHaveLength), or null if not resizing
|
||||||
|
*/
|
||||||
|
ResizeDimensions getResizeDimensions();
|
||||||
|
|
||||||
void editSelection();
|
void editSelection();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -37,16 +37,14 @@ import com.thoughtworks.xstream.annotations.XStreamOmitField;
|
|||||||
import org.diylc.common.IPlugInPort;
|
import org.diylc.common.IPlugInPort;
|
||||||
import org.diylc.common.LineStyle;
|
import org.diylc.common.LineStyle;
|
||||||
import org.diylc.common.ObjectCache;
|
import org.diylc.common.ObjectCache;
|
||||||
import org.diylc.core.ComponentState;
|
import org.diylc.core.*;
|
||||||
import org.diylc.core.IDrawingObserver;
|
|
||||||
import org.diylc.core.Project;
|
|
||||||
import org.diylc.core.VisibilityPolicy;
|
|
||||||
import org.diylc.core.annotations.EditableProperty;
|
import org.diylc.core.annotations.EditableProperty;
|
||||||
import org.diylc.core.measures.Size;
|
import org.diylc.core.measures.Size;
|
||||||
import org.diylc.core.measures.SizeUnit;
|
import org.diylc.core.measures.SizeUnit;
|
||||||
import org.diylc.utils.Constants;
|
import org.diylc.utils.Constants;
|
||||||
|
|
||||||
public abstract class AbstractCurvedComponent<T> extends AbstractTransparentComponent<T> {
|
public abstract class AbstractCurvedComponent<T> extends AbstractTransparentComponent<T> implements
|
||||||
|
IHaveLength {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@@ -337,8 +335,8 @@ public abstract class AbstractCurvedComponent<T> extends AbstractTransparentComp
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
@EditableProperty
|
@EditableProperty(name = "Length")
|
||||||
public Size getLength() {
|
public Size calculateLength() {
|
||||||
double d = 0;
|
double d = 0;
|
||||||
try {
|
try {
|
||||||
Point2D[] p = getControlPoints();
|
Point2D[] p = getControlPoints();
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
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.core;
|
||||||
|
|
||||||
|
import org.diylc.core.measures.Size;
|
||||||
|
|
||||||
|
public interface IHaveLength {
|
||||||
|
|
||||||
|
Size calculateLength();
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.core.measures;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Record containing resize dimensions for a component being resized.
|
||||||
|
*
|
||||||
|
* @param width the width of the component (in mm or in, depending on configuration)
|
||||||
|
* @param height the height of the component (in mm or in, depending on configuration)
|
||||||
|
* @param length the length of the component (if it implements IHaveLength), null otherwise
|
||||||
|
*/
|
||||||
|
public record ResizeDimensions(Size width, Size height, Size length) {
|
||||||
|
}
|
||||||
|
|
||||||
@@ -59,16 +59,10 @@ import com.thoughtworks.xstream.security.AnyTypePermission;
|
|||||||
|
|
||||||
import org.diylc.clipboard.ComponentTransferable;
|
import org.diylc.clipboard.ComponentTransferable;
|
||||||
import org.diylc.common.*;
|
import org.diylc.common.*;
|
||||||
import org.diylc.core.ExpansionMode;
|
import org.diylc.core.*;
|
||||||
import org.diylc.core.IDIYComponent;
|
|
||||||
import org.diylc.core.IDatasheetSupport;
|
|
||||||
import org.diylc.core.IView;
|
|
||||||
import org.diylc.core.Project;
|
|
||||||
import org.diylc.core.Template;
|
|
||||||
import org.diylc.core.Theme;
|
|
||||||
import org.diylc.core.VisibilityPolicy;
|
|
||||||
import org.diylc.core.annotations.IAutoCreator;
|
import org.diylc.core.annotations.IAutoCreator;
|
||||||
import org.diylc.core.gerber.GerberExporter;
|
import org.diylc.core.gerber.GerberExporter;
|
||||||
|
import org.diylc.core.measures.ResizeDimensions;
|
||||||
import org.diylc.core.measures.Size;
|
import org.diylc.core.measures.Size;
|
||||||
import org.diylc.core.measures.SizeUnit;
|
import org.diylc.core.measures.SizeUnit;
|
||||||
import org.diylc.filter.IComponentFilter;
|
import org.diylc.filter.IComponentFilter;
|
||||||
@@ -928,29 +922,36 @@ public class Presenter implements IPlugInPort {
|
|||||||
messageDispatcher.dispatchMessage(EventType.REPAINT);
|
messageDispatcher.dispatchMessage(EventType.REPAINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Rectangle2D getSelectionBounds(boolean applyZoom) {
|
public Rectangle2D getSelectionBounds(boolean applyZoom) {
|
||||||
if (selectedComponents == null || selectedComponents.isEmpty())
|
return getComponentBounds(selectedComponents, applyZoom);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Rectangle2D getComponentBounds(Collection<IDIYComponent<?>> components, boolean applyZoom) {
|
||||||
|
if (components == null || components.isEmpty())
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
int minX = Integer.MAX_VALUE;
|
int minX = Integer.MAX_VALUE;
|
||||||
int maxX = Integer.MIN_VALUE;
|
int maxX = Integer.MIN_VALUE;
|
||||||
int minY = Integer.MAX_VALUE;
|
int minY = Integer.MAX_VALUE;
|
||||||
int maxY = Integer.MIN_VALUE;
|
int maxY = Integer.MIN_VALUE;
|
||||||
for (IDIYComponent<?> c : selectedComponents) {
|
|
||||||
|
for (IDIYComponent<?> c : components) {
|
||||||
|
|
||||||
ComponentArea compArea = drawingManager.getComponentArea(c);
|
ComponentArea compArea = drawingManager.getComponentArea(c);
|
||||||
if (compArea != null && compArea.getOutlineArea() != null) {
|
if (compArea == null || compArea.getOutlineArea() == null) {
|
||||||
Rectangle rect = compArea.getOutlineArea().getBounds();
|
|
||||||
if (rect.x < minX)
|
|
||||||
minX = rect.x;
|
|
||||||
if (rect.x + rect.width > maxX)
|
|
||||||
maxX = rect.x + rect.width;
|
|
||||||
if (rect.y < minY)
|
|
||||||
minY = rect.y;
|
|
||||||
if (rect.y + rect.height > maxY)
|
|
||||||
maxY = rect.y + rect.height;
|
|
||||||
} else if (currentProject.getComponents().contains(c))
|
|
||||||
LOG.debug("Area is null for " + c.getName() + " of type " + c.getClass().getName());
|
LOG.debug("Area is null for " + c.getName() + " of type " + c.getClass().getName());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle rect = compArea.getOutlineArea().getBounds();
|
||||||
|
if (rect.x < minX)
|
||||||
|
minX = rect.x;
|
||||||
|
if (rect.x + rect.width > maxX)
|
||||||
|
maxX = rect.x + rect.width;
|
||||||
|
if (rect.y < minY)
|
||||||
|
minY = rect.y;
|
||||||
|
if (rect.y + rect.height > maxY)
|
||||||
|
maxY = rect.y + rect.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (configManager.readBoolean(EXTRA_SPACE_KEY, true)) {
|
if (configManager.readBoolean(EXTRA_SPACE_KEY, true)) {
|
||||||
@@ -1019,8 +1020,9 @@ public class Presenter implements IPlugInPort {
|
|||||||
}
|
}
|
||||||
updateSelection(matching);
|
updateSelection(matching);
|
||||||
messageDispatcher.dispatchMessage(EventType.REPAINT, true);
|
messageDispatcher.dispatchMessage(EventType.REPAINT, true);
|
||||||
if (matching.size() > 0)
|
if (!matching.isEmpty()) {
|
||||||
messageDispatcher.dispatchMessage(EventType.SCROLL_TO, getSelectionBounds(true));
|
messageDispatcher.dispatchMessage(EventType.SCROLL_TO, getSelectionBounds(true));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -1237,11 +1239,14 @@ public class Presenter implements IPlugInPort {
|
|||||||
Map<String, Object> params = new HashMap<String, Object>();
|
Map<String, Object> params = new HashMap<String, Object>();
|
||||||
params.put("point", point);
|
params.put("point", point);
|
||||||
test.addStep(DIYTest.DRAG_OVER, params);
|
test.addStep(DIYTest.DRAG_OVER, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (point == null || operationMode == OperationMode.HIGHLIGHT_CONNECTED_AREAS) {
|
if (point == null || operationMode == OperationMode.HIGHLIGHT_CONNECTED_AREAS) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean resizeInProgress = false;
|
||||||
|
|
||||||
Point2D scaledPoint = scalePoint(point);
|
Point2D scaledPoint = scalePoint(point);
|
||||||
if (controlPointMap != null && !controlPointMap.isEmpty()) {
|
if (controlPointMap != null && !controlPointMap.isEmpty()) {
|
||||||
// We're dragging control point(s).
|
// We're dragging control point(s).
|
||||||
@@ -1252,6 +1257,13 @@ public class Presenter implements IPlugInPort {
|
|||||||
if (actualD == null)
|
if (actualD == null)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
// if there's at least one component with only one control point being dragged it means that we are resizing
|
||||||
|
if (controlPointMap.size() == 1 && controlPointMap.entrySet().stream()
|
||||||
|
.anyMatch(entry -> entry.getValue().size() == 1
|
||||||
|
&& entry.getKey().getControlPointCount() > 1)) {
|
||||||
|
resizeInProgress = true;
|
||||||
|
}
|
||||||
|
|
||||||
previousDragPoint.setLocation(previousDragPoint.getX() + actualD.getX(), previousDragPoint.getY() + actualD.getY());
|
previousDragPoint.setLocation(previousDragPoint.getX() + actualD.getX(), previousDragPoint.getY() + actualD.getY());
|
||||||
} else if (selectedComponents.isEmpty() && instantiationManager.getComponentTypeSlot() == null
|
} else if (selectedComponents.isEmpty() && instantiationManager.getComponentTypeSlot() == null
|
||||||
&& previousDragPoint != null) {
|
&& previousDragPoint != null) {
|
||||||
@@ -1269,10 +1281,50 @@ public class Presenter implements IPlugInPort {
|
|||||||
this.previousScaledPoint = scalePoint(point);
|
this.previousScaledPoint = scalePoint(point);
|
||||||
instantiationManager.updateSingleClick(previousScaledPoint, isSnapToGrid(), currentProject.getGridSpacing());
|
instantiationManager.updateSingleClick(previousScaledPoint, isSnapToGrid(), currentProject.getGridSpacing());
|
||||||
}
|
}
|
||||||
messageDispatcher.dispatchMessage(EventType.REPAINT);
|
|
||||||
|
messageDispatcher.dispatchMessage(EventType.REPAINT, false, resizeInProgress);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ResizeDimensions getResizeDimensions() {
|
||||||
|
|
||||||
|
if (controlPointMap == null || controlPointMap.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the component being resized (one with a single control point being dragged)
|
||||||
|
IDIYComponent<?> resizingComponent = null;
|
||||||
|
for (Map.Entry<IDIYComponent<?>, Set<Integer>> entry : controlPointMap.entrySet()) {
|
||||||
|
if (entry.getValue().size() == 1 && entry.getKey().getControlPointCount() > 1) {
|
||||||
|
resizingComponent = entry.getKey();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resizingComponent == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle2D componentBounds = getComponentBounds(controlPointMap.keySet(), false);
|
||||||
|
if (componentBounds == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert pixel dimensions to Size (mm or in based on configuration)
|
||||||
|
boolean metric = configManager.readBoolean(METRIC_KEY, true);
|
||||||
|
SizeUnit unit = metric ? SizeUnit.mm : SizeUnit.in;
|
||||||
|
Size width = Size.fromPixels(componentBounds.getWidth(), unit);
|
||||||
|
Size height = Size.fromPixels(componentBounds.getHeight(), unit);
|
||||||
|
|
||||||
|
// Get length if component implements IHaveLength
|
||||||
|
Size length = null;
|
||||||
|
if (resizingComponent instanceof IHaveLength iHaveLength) {
|
||||||
|
length = iHaveLength.calculateLength();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ResizeDimensions(width, height, length);
|
||||||
|
}
|
||||||
|
|
||||||
private Point2D moveComponents(Map<IDIYComponent<?>, Set<Integer>> controlPointMap, int dx, int dy, boolean snapToGrid, boolean snapToObjects) {
|
private Point2D moveComponents(Map<IDIYComponent<?>, Set<Integer>> controlPointMap, int dx, int dy, boolean snapToGrid, boolean snapToObjects) {
|
||||||
// After we make the transfer and snap to grid, calculate actual dx
|
// After we make the transfer and snap to grid, calculate actual dx
|
||||||
// and dy. We'll use them to translate the previous drag point.
|
// and dy. We'll use them to translate the previous drag point.
|
||||||
@@ -2171,6 +2223,10 @@ public class Presenter implements IPlugInPort {
|
|||||||
}
|
}
|
||||||
Rectangle2D rect = getSelectionBounds(false);
|
Rectangle2D rect = getSelectionBounds(false);
|
||||||
|
|
||||||
|
if (rect == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
double width = rect.getWidth();
|
double width = rect.getWidth();
|
||||||
double height = rect.getHeight();
|
double height = rect.getHeight();
|
||||||
|
|
||||||
|
|||||||
@@ -484,5 +484,21 @@
|
|||||||
</changes>
|
</changes>
|
||||||
<url>https://github.com/bancika/diy-layout-creator/releases</url>
|
<url>https://github.com/bancika/diy-layout-creator/releases</url>
|
||||||
</org.diylc.appframework.update.Version>
|
</org.diylc.appframework.update.Version>
|
||||||
|
<org.diylc.appframework.update.Version>
|
||||||
|
<versionNumber>
|
||||||
|
<major>5</major>
|
||||||
|
<minor>9</minor>
|
||||||
|
<build>0</build>
|
||||||
|
</versionNumber>
|
||||||
|
<releaseDate>2025-12-30 00:00:00.000 CET</releaseDate>
|
||||||
|
<name></name>
|
||||||
|
<changes>
|
||||||
|
<org.diylc.appframework.update.Change>
|
||||||
|
<changeType>NEW_FEATURE</changeType>
|
||||||
|
<description>Added balloon tooltip next to cursor showing component width, height and length (where available) while resizing; can be disabled from Config menu</description>
|
||||||
|
</org.diylc.appframework.update.Change>
|
||||||
|
</changes>
|
||||||
|
<url>https://github.com/bancika/diy-layout-creator/releases</url>
|
||||||
|
</org.diylc.appframework.update.Version>
|
||||||
</a>
|
</a>
|
||||||
</java.util.Arrays_-ArrayList>
|
</java.util.Arrays_-ArrayList>
|
||||||
|
|||||||
+29
-6
@@ -43,11 +43,7 @@ import org.diylc.common.IPlugInPort;
|
|||||||
import org.diylc.common.LineStyle;
|
import org.diylc.common.LineStyle;
|
||||||
import org.diylc.common.ObjectCache;
|
import org.diylc.common.ObjectCache;
|
||||||
import org.diylc.common.VerticalAlignment;
|
import org.diylc.common.VerticalAlignment;
|
||||||
import org.diylc.core.ComponentState;
|
import org.diylc.core.*;
|
||||||
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.EditableProperty;
|
||||||
import org.diylc.core.annotations.PositiveNonZeroMeasureValidator;
|
import org.diylc.core.annotations.PositiveNonZeroMeasureValidator;
|
||||||
import org.diylc.core.measures.Size;
|
import org.diylc.core.measures.Size;
|
||||||
@@ -62,7 +58,8 @@ import org.diylc.utils.Constants;
|
|||||||
*
|
*
|
||||||
* @author Branislav Stojkovic
|
* @author Branislav Stojkovic
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractLeadedComponent<T> extends AbstractLabeledComponent<T> {
|
public abstract class AbstractLeadedComponent<T> extends AbstractLabeledComponent<T> implements
|
||||||
|
IHaveLength {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@@ -640,6 +637,32 @@ public abstract class AbstractLeadedComponent<T> extends AbstractLabeledComponen
|
|||||||
this.length = length;
|
this.length = length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Size calculateLength() {
|
||||||
|
|
||||||
|
try {
|
||||||
|
Point2D[] points = getPoints();
|
||||||
|
if (points.length < 2) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate distance between ending points
|
||||||
|
double distanceInPixels = points[0].distance(points[1]);
|
||||||
|
|
||||||
|
// Convert to Size with appropriate unit (mm or in based on configuration)
|
||||||
|
SizeUnit unit;
|
||||||
|
if (ConfigurationManager.getInstance().readBoolean(IPlugInPort.METRIC_KEY, true)) {
|
||||||
|
unit = SizeUnit.mm;
|
||||||
|
} else {
|
||||||
|
unit = SizeUnit.in;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Size.fromPixels(distanceInPixels, unit);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@EditableProperty(name = "Width", defaultable = true, validatorClass = PositiveNonZeroMeasureValidator.class, sortOrder = 102)
|
@EditableProperty(name = "Width", defaultable = true, validatorClass = PositiveNonZeroMeasureValidator.class, sortOrder = 102)
|
||||||
public Size getWidth() {
|
public Size getWidth() {
|
||||||
return width;
|
return width;
|
||||||
|
|||||||
@@ -69,18 +69,18 @@ public class BlankBoard extends AbstractBoard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1));
|
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1));
|
||||||
if (componentState != ComponentState.DRAGGING) {
|
// if (componentState != ComponentState.DRAGGING) {
|
||||||
Composite oldComposite = g2d.getComposite();
|
Composite oldComposite = g2d.getComposite();
|
||||||
if (alpha < MAX_ALPHA) {
|
if (alpha < MAX_ALPHA) {
|
||||||
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA));
|
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA));
|
||||||
}
|
|
||||||
g2d.setColor(boardColor);
|
|
||||||
if (getType() == Type.SQUARE)
|
|
||||||
g2d.fillRect((int)firstPoint.getX(), (int)firstPoint.getY(), (int)(finalSecondPoint.getX() - firstPoint.getX()), (int)(finalSecondPoint.getY() - firstPoint.getY()));
|
|
||||||
else
|
|
||||||
g2d.fillOval((int)firstPoint.getX(), (int)firstPoint.getY(), (int)(finalSecondPoint.getX() - firstPoint.getX()), (int)(finalSecondPoint.getY() - firstPoint.getY()));
|
|
||||||
g2d.setComposite(oldComposite);
|
|
||||||
}
|
}
|
||||||
|
g2d.setColor(boardColor);
|
||||||
|
if (getType() == Type.SQUARE)
|
||||||
|
g2d.fillRect((int)firstPoint.getX(), (int)firstPoint.getY(), (int)(finalSecondPoint.getX() - firstPoint.getX()), (int)(finalSecondPoint.getY() - firstPoint.getY()));
|
||||||
|
else
|
||||||
|
g2d.fillOval((int)firstPoint.getX(), (int)firstPoint.getY(), (int)(finalSecondPoint.getX() - firstPoint.getX()), (int)(finalSecondPoint.getY() - firstPoint.getY()));
|
||||||
|
g2d.setComposite(oldComposite);
|
||||||
|
// }
|
||||||
// Do not track any changes that follow because the whole board has been
|
// Do not track any changes that follow because the whole board has been
|
||||||
// tracked so far.
|
// tracked so far.
|
||||||
drawingObserver.stopTracking();
|
drawingObserver.stopTracking();
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ import org.apache.log4j.Logger;
|
|||||||
import org.diylc.appframework.miscutils.IConfigListener;
|
import org.diylc.appframework.miscutils.IConfigListener;
|
||||||
import org.diylc.appframework.miscutils.IConfigurationManager;
|
import org.diylc.appframework.miscutils.IConfigurationManager;
|
||||||
import org.diylc.appframework.miscutils.Utils;
|
import org.diylc.appframework.miscutils.Utils;
|
||||||
|
import org.diylc.core.measures.ResizeDimensions;
|
||||||
import org.diylc.swingframework.ruler.IRulerListener;
|
import org.diylc.swingframework.ruler.IRulerListener;
|
||||||
import org.diylc.swingframework.ruler.Ruler.InchSubdivision;
|
import org.diylc.swingframework.ruler.Ruler.InchSubdivision;
|
||||||
import org.diylc.swingframework.ruler.RulerScrollPane;
|
import org.diylc.swingframework.ruler.RulerScrollPane;
|
||||||
@@ -53,7 +54,6 @@ import org.diylc.common.BadPositionException;
|
|||||||
import org.diylc.common.EventType;
|
import org.diylc.common.EventType;
|
||||||
import org.diylc.common.IPlugIn;
|
import org.diylc.common.IPlugIn;
|
||||||
import org.diylc.common.IPlugInPort;
|
import org.diylc.common.IPlugInPort;
|
||||||
import org.diylc.core.IDIYComponent;
|
|
||||||
import org.diylc.core.measures.Size;
|
import org.diylc.core.measures.Size;
|
||||||
import org.diylc.core.measures.SizeUnit;
|
import org.diylc.core.measures.SizeUnit;
|
||||||
import org.diylc.presenter.Presenter;
|
import org.diylc.presenter.Presenter;
|
||||||
@@ -68,6 +68,8 @@ public class CanvasPlugin implements IPlugIn{
|
|||||||
private RulerScrollPane scrollPane;
|
private RulerScrollPane scrollPane;
|
||||||
private CanvasPanel canvasPanel;
|
private CanvasPanel canvasPanel;
|
||||||
private ComponentPopupMenu popupMenu;
|
private ComponentPopupMenu popupMenu;
|
||||||
|
private ResizeInfoTooltip resizeInfoTooltip;
|
||||||
|
private boolean resizingInProgress = false;
|
||||||
|
|
||||||
private IPlugInPort plugInPort;
|
private IPlugInPort plugInPort;
|
||||||
private ISwingUI swingUI;
|
private ISwingUI swingUI;
|
||||||
@@ -193,6 +195,7 @@ public class CanvasPlugin implements IPlugIn{
|
|||||||
public CanvasPanel getCanvasPanel() {
|
public CanvasPanel getCanvasPanel() {
|
||||||
if (canvasPanel == null) {
|
if (canvasPanel == null) {
|
||||||
canvasPanel = new CanvasPanel(plugInPort, configManager);
|
canvasPanel = new CanvasPanel(plugInPort, configManager);
|
||||||
|
resizeInfoTooltip = new ResizeInfoTooltip(canvasPanel, configManager);
|
||||||
canvasPanel.addMouseListener(new MouseAdapter() {
|
canvasPanel.addMouseListener(new MouseAdapter() {
|
||||||
|
|
||||||
private MouseEvent pressedEvent;
|
private MouseEvent pressedEvent;
|
||||||
@@ -277,6 +280,15 @@ public class CanvasPlugin implements IPlugIn{
|
|||||||
e.isShiftDown(), e.isAltDown()));
|
e.isShiftDown(), e.isAltDown()));
|
||||||
plugInPort.mouseMoved(e.getPoint(), Utils.isMac() ? e.isMetaDown() : e.isControlDown(),
|
plugInPort.mouseMoved(e.getPoint(), Utils.isMac() ? e.isMetaDown() : e.isControlDown(),
|
||||||
e.isShiftDown(), e.isAltDown());
|
e.isShiftDown(), e.isAltDown());
|
||||||
|
|
||||||
|
// Update tooltip position if resizing is in progress and tooltip is enabled, otherwise hide it
|
||||||
|
if (resizeInfoTooltip != null) {
|
||||||
|
if (resizingInProgress && configManager.readBoolean(IPlugInPort.SHOW_RESIZE_DIMENSIONS_TOOLTIP_KEY, true)) {
|
||||||
|
resizeInfoTooltip.updatePosition(e.getPoint());
|
||||||
|
} else {
|
||||||
|
resizeInfoTooltip.hideTooltip();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -505,11 +517,13 @@ public class CanvasPlugin implements IPlugIn{
|
|||||||
canvasPanel.repaint();
|
canvasPanel.repaint();
|
||||||
// Refresh selection bounds after we're done with painting to ensure we have traced the
|
// Refresh selection bounds after we're done with painting to ensure we have traced the
|
||||||
// component areas
|
// component areas
|
||||||
|
boolean panToSelection = params.length > 0 && Boolean.TRUE.equals(params[0]);
|
||||||
|
this.resizingInProgress = params.length > 1 && Boolean.TRUE.equals(params[1]);
|
||||||
SwingUtilities.invokeLater(new Runnable() {
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (params.length > 0 && Boolean.TRUE.equals(params[0])) {
|
if (panToSelection) {
|
||||||
Rectangle2D selectionBounds = plugInPort.getSelectionBounds(true);
|
Rectangle2D selectionBounds = plugInPort.getSelectionBounds(true);
|
||||||
if (selectionBounds != null) {
|
if (selectionBounds != null) {
|
||||||
Rectangle visibleRect = scrollPane.getVisibleRect();
|
Rectangle visibleRect = scrollPane.getVisibleRect();
|
||||||
@@ -519,8 +533,28 @@ public class CanvasPlugin implements IPlugIn{
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (configManager.readBoolean(IPlugInPort.SHOW_RULERS_KEY, true))
|
if (configManager.readBoolean(IPlugInPort.SHOW_RULERS_KEY, true)) {
|
||||||
scrollPane.setSelectionRectangle(plugInPort.getSelectionBounds(true));
|
scrollPane.setSelectionRectangle(plugInPort.getSelectionBounds(true));
|
||||||
|
}
|
||||||
|
if (CanvasPlugin.this.resizingInProgress && getCanvasPanel().getMousePosition() != null) {
|
||||||
|
// Only show tooltip if enabled in configuration
|
||||||
|
if (configManager.readBoolean(IPlugInPort.SHOW_RESIZE_DIMENSIONS_TOOLTIP_KEY, true)) {
|
||||||
|
ResizeDimensions resizeDimensions = plugInPort.getResizeDimensions();
|
||||||
|
if (resizeInfoTooltip != null) {
|
||||||
|
resizeInfoTooltip.update(resizeDimensions, getCanvasPanel().getMousePosition());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Hide tooltip if disabled
|
||||||
|
if (resizeInfoTooltip != null) {
|
||||||
|
resizeInfoTooltip.hideTooltip();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Hide tooltip when not resizing
|
||||||
|
if (resizeInfoTooltip != null) {
|
||||||
|
resizeInfoTooltip.hideTooltip();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
@@ -563,25 +597,4 @@ public class CanvasPlugin implements IPlugIn{
|
|||||||
double extraSpace = CanvasPlugin.this.plugInPort.getExtraSpace();
|
double extraSpace = CanvasPlugin.this.plugInPort.getExtraSpace();
|
||||||
getScrollPane().setZeroLocation(new Point2D.Double(extraSpace, extraSpace));
|
getScrollPane().setZeroLocation(new Point2D.Double(extraSpace, extraSpace));
|
||||||
}
|
}
|
||||||
|
|
||||||
class LockAction extends AbstractAction {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private IDIYComponent<?> component;
|
|
||||||
private boolean locked;
|
|
||||||
|
|
||||||
public LockAction(IDIYComponent<?> component, boolean locked) {
|
|
||||||
super();
|
|
||||||
this.locked = locked;
|
|
||||||
this.component = component;
|
|
||||||
putValue(AbstractAction.NAME, component.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
|
||||||
plugInPort.lockComponent(component, locked);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+225
@@ -0,0 +1,225 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.swing.plugins.canvas;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.awt.Component;
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.Font;
|
||||||
|
import java.awt.Graphics;
|
||||||
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.Point;
|
||||||
|
import java.awt.RenderingHints;
|
||||||
|
import java.awt.Window;
|
||||||
|
import java.text.DecimalFormat;
|
||||||
|
import javax.swing.BorderFactory;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JWindow;
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
|
import javax.swing.UIManager;
|
||||||
|
import org.diylc.appframework.miscutils.IConfigurationManager;
|
||||||
|
import org.diylc.core.measures.ResizeDimensions;
|
||||||
|
import org.diylc.core.measures.Size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A lightweight tooltip window that displays resize dimensions and tracks the mouse cursor.
|
||||||
|
*/
|
||||||
|
public class ResizeInfoTooltip {
|
||||||
|
|
||||||
|
private static final int OFFSET_X = 16;
|
||||||
|
private static final int OFFSET_Y = 16;
|
||||||
|
private static final DecimalFormat SIZE_FORMAT = new DecimalFormat("0.00");
|
||||||
|
|
||||||
|
private JWindow tooltipWindow;
|
||||||
|
private JLabel tooltipLabel;
|
||||||
|
private Component parentComponent;
|
||||||
|
private ResizeDimensions currentDimensions;
|
||||||
|
|
||||||
|
public ResizeInfoTooltip(Component parentComponent, IConfigurationManager<?> configManager) {
|
||||||
|
this.parentComponent = parentComponent;
|
||||||
|
initializeTooltip();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initializeTooltip() {
|
||||||
|
Window parentWindow = SwingUtilities.getWindowAncestor(parentComponent);
|
||||||
|
if (parentWindow == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tooltipWindow = new JWindow(parentWindow);
|
||||||
|
tooltipLabel = new JLabel() {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void paintComponent(Graphics g) {
|
||||||
|
Graphics2D g2d = (Graphics2D) g.create();
|
||||||
|
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||||
|
super.paintComponent(g2d);
|
||||||
|
g2d.dispose();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Use system tooltip font and colors
|
||||||
|
Font tooltipFont = UIManager.getFont("ToolTip.font");
|
||||||
|
if (tooltipFont != null) {
|
||||||
|
tooltipLabel.setFont(tooltipFont);
|
||||||
|
}
|
||||||
|
Color tooltipBackground = UIManager.getColor("ToolTip.background");
|
||||||
|
Color tooltipForeground = UIManager.getColor("ToolTip.foreground");
|
||||||
|
Color tooltipBorderColor = UIManager.getColor("ToolTip.border");
|
||||||
|
if (tooltipBorderColor == null) {
|
||||||
|
tooltipBorderColor = Color.GRAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
tooltipLabel.setBorder(BorderFactory.createCompoundBorder(
|
||||||
|
BorderFactory.createLineBorder(tooltipBorderColor, 1),
|
||||||
|
BorderFactory.createEmptyBorder(4, 6, 4, 6)));
|
||||||
|
tooltipLabel.setOpaque(true);
|
||||||
|
tooltipLabel.setBackground(tooltipBackground != null ? tooltipBackground : new Color(255, 255, 220));
|
||||||
|
tooltipLabel.setForeground(tooltipForeground != null ? tooltipForeground : Color.BLACK);
|
||||||
|
|
||||||
|
tooltipWindow.add(tooltipLabel);
|
||||||
|
tooltipWindow.setFocusableWindowState(false);
|
||||||
|
tooltipWindow.setAlwaysOnTop(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the tooltip with new dimensions and mouse position.
|
||||||
|
*/
|
||||||
|
public void update(ResizeDimensions dimensions, Point mousePosition) {
|
||||||
|
this.currentDimensions = dimensions;
|
||||||
|
|
||||||
|
if (dimensions == null || mousePosition == null) {
|
||||||
|
hideTooltip();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tooltipWindow == null) {
|
||||||
|
initializeTooltip();
|
||||||
|
if (tooltipWindow == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format the dimensions
|
||||||
|
String text = formatDimensions(dimensions);
|
||||||
|
tooltipLabel.setText(text);
|
||||||
|
tooltipLabel.setPreferredSize(null); // Reset to calculate preferred size
|
||||||
|
tooltipWindow.pack();
|
||||||
|
|
||||||
|
// Position the tooltip near the mouse cursor
|
||||||
|
updateTooltipPosition(mousePosition);
|
||||||
|
tooltipWindow.setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the tooltip position based on the current mouse position.
|
||||||
|
*/
|
||||||
|
public void updatePosition(Point mousePosition) {
|
||||||
|
if (currentDimensions != null && mousePosition != null && tooltipWindow != null && tooltipWindow.isVisible()) {
|
||||||
|
updateTooltipPosition(mousePosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateTooltipPosition(Point mousePosition) {
|
||||||
|
if (tooltipWindow == null || parentComponent == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert mouse position to screen coordinates
|
||||||
|
Point screenPoint = new Point(mousePosition);
|
||||||
|
SwingUtilities.convertPointToScreen(screenPoint, parentComponent);
|
||||||
|
|
||||||
|
// Position tooltip 16 pixels down and right from cursor
|
||||||
|
int x = screenPoint.x + OFFSET_X;
|
||||||
|
int y = screenPoint.y + OFFSET_Y;
|
||||||
|
|
||||||
|
// Ensure tooltip stays on screen
|
||||||
|
Dimension tooltipSize = tooltipWindow.getSize();
|
||||||
|
if (tooltipSize == null) {
|
||||||
|
tooltipWindow.pack();
|
||||||
|
tooltipSize = tooltipWindow.getSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tooltipSize != null) {
|
||||||
|
java.awt.Toolkit toolkit = java.awt.Toolkit.getDefaultToolkit();
|
||||||
|
Dimension screenSize = toolkit.getScreenSize();
|
||||||
|
|
||||||
|
// Adjust if tooltip would go off screen
|
||||||
|
if (x + tooltipSize.width > screenSize.width) {
|
||||||
|
x = screenPoint.x - tooltipSize.width - OFFSET_X;
|
||||||
|
}
|
||||||
|
if (y + tooltipSize.height > screenSize.height) {
|
||||||
|
y = screenPoint.y - tooltipSize.height - OFFSET_Y;
|
||||||
|
}
|
||||||
|
if (x < 0) {
|
||||||
|
x = 0;
|
||||||
|
}
|
||||||
|
if (y < 0) {
|
||||||
|
y = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tooltipWindow.setLocation(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String formatDimensions(ResizeDimensions dimensions) {
|
||||||
|
StringBuilder sb = new StringBuilder("<html>");
|
||||||
|
|
||||||
|
// Format width
|
||||||
|
Size width = dimensions.width();
|
||||||
|
String widthUnit = width.getUnit().toString();
|
||||||
|
sb.append(String.format("W: %s %s", SIZE_FORMAT.format(width.getValue()), widthUnit));
|
||||||
|
|
||||||
|
// Format height
|
||||||
|
Size height = dimensions.height();
|
||||||
|
String heightUnit = height.getUnit().toString();
|
||||||
|
sb.append(String.format("<br>H: %s %s", SIZE_FORMAT.format(height.getValue()), heightUnit));
|
||||||
|
|
||||||
|
// Format length if available
|
||||||
|
Size length = dimensions.length();
|
||||||
|
if (length != null) {
|
||||||
|
String lengthUnit = length.getUnit().toString();
|
||||||
|
sb.append(String.format("<br>L: %s %s", SIZE_FORMAT.format(length.getValue()), lengthUnit));
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.append("</html>");
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hides the tooltip.
|
||||||
|
*/
|
||||||
|
public void hideTooltip() {
|
||||||
|
if (tooltipWindow != null) {
|
||||||
|
tooltipWindow.setVisible(false);
|
||||||
|
}
|
||||||
|
currentDimensions = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disposes the tooltip window.
|
||||||
|
*/
|
||||||
|
public void dispose() {
|
||||||
|
if (tooltipWindow != null) {
|
||||||
|
tooltipWindow.dispose();
|
||||||
|
tooltipWindow = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -158,6 +158,10 @@ public class ConfigPlugin implements IPlugIn {
|
|||||||
ActionFactory.getInstance().createConfigAction(plugInPort, "Show Rulers", IPlugInPort.SHOW_RULERS_KEY, true),
|
ActionFactory.getInstance().createConfigAction(plugInPort, "Show Rulers", IPlugInPort.SHOW_RULERS_KEY, true),
|
||||||
CONFIG_MENU);
|
CONFIG_MENU);
|
||||||
|
|
||||||
|
swingUI.injectMenuAction(
|
||||||
|
ActionFactory.getInstance().createConfigAction(plugInPort, "Show Resize Dimensions",
|
||||||
|
IPlugInPort.SHOW_RESIZE_DIMENSIONS_TOOLTIP_KEY, true), CONFIG_MENU);
|
||||||
|
|
||||||
swingUI.injectSubmenu(SNAP_MENU, IconLoader.GraphEdgeDirected.getIcon(), CONFIG_MENU);
|
swingUI.injectSubmenu(SNAP_MENU, IconLoader.GraphEdgeDirected.getIcon(), CONFIG_MENU);
|
||||||
swingUI.injectMenuAction(
|
swingUI.injectMenuAction(
|
||||||
ActionFactory.getInstance().createToggleAction(IPlugInPort.SNAP_TO_NONE, IPlugInPort.SNAP_TO_KEY, SNAP_MENU, IPlugInPort.SNAP_TO_DEFAULT),
|
ActionFactory.getInstance().createToggleAction(IPlugInPort.SNAP_TO_NONE, IPlugInPort.SNAP_TO_KEY, SNAP_MENU, IPlugInPort.SNAP_TO_DEFAULT),
|
||||||
|
|||||||
@@ -363,6 +363,7 @@ Shaft Up|Achse nach oben
|
|||||||
Shape|Form
|
Shape|Form
|
||||||
Shapes|Formen
|
Shapes|Formen
|
||||||
Show Grid|Raster anzeigen
|
Show Grid|Raster anzeigen
|
||||||
|
Show Resize Dimensions|Größenänderungsdimensionen anzeigen
|
||||||
Show Rulers|Lineale anzeigen
|
Show Rulers|Lineale anzeigen
|
||||||
Shroud|Wanne
|
Shroud|Wanne
|
||||||
Shrouded|Abgeschirmt
|
Shrouded|Abgeschirmt
|
||||||
|
|||||||
@@ -352,6 +352,7 @@ Shape
|
|||||||
Shapes
|
Shapes
|
||||||
Show Bracket
|
Show Bracket
|
||||||
Show Grid
|
Show Grid
|
||||||
|
Show Resize Dimensions
|
||||||
Show Rulers
|
Show Rulers
|
||||||
Shroud
|
Shroud
|
||||||
Shrouded
|
Shrouded
|
||||||
|
|||||||
@@ -351,6 +351,7 @@ Shaft Up|Eje Arriba
|
|||||||
Shape|Forma
|
Shape|Forma
|
||||||
Shapes|Formas
|
Shapes|Formas
|
||||||
Show Grid|Mostrar Cuadrícula
|
Show Grid|Mostrar Cuadrícula
|
||||||
|
Show Resize Dimensions|Mostrar Dimensiones de Redimensionamiento
|
||||||
Show Rulers|Mostrar Reglas
|
Show Rulers|Mostrar Reglas
|
||||||
Shroud|Envoltura
|
Shroud|Envoltura
|
||||||
Shrouded|Con Envoltura
|
Shrouded|Con Envoltura
|
||||||
|
|||||||
@@ -348,6 +348,7 @@ Shaft Up|Tige vers le haut
|
|||||||
Shape|Forme
|
Shape|Forme
|
||||||
Shapes|Formes
|
Shapes|Formes
|
||||||
Show Grid|Afficher la grille
|
Show Grid|Afficher la grille
|
||||||
|
Show Resize Dimensions|Afficher les dimensions de redimensionnement
|
||||||
Show Rulers|Afficher les règles
|
Show Rulers|Afficher les règles
|
||||||
Shroud|Enveloppe
|
Shroud|Enveloppe
|
||||||
Shrouded|Enveloppé
|
Shrouded|Enveloppé
|
||||||
|
|||||||
@@ -363,6 +363,7 @@ Shaft Up|Shaft Up
|
|||||||
Shape|forma
|
Shape|forma
|
||||||
Shapes|forme
|
Shapes|forme
|
||||||
Show Grid|Mostra griglia
|
Show Grid|Mostra griglia
|
||||||
|
Show Resize Dimensions|Mostra dimensioni ridimensionamento
|
||||||
Show Rulers|Mostra righelli
|
Show Rulers|Mostra righelli
|
||||||
Shroud|Copri
|
Shroud|Copri
|
||||||
Shrouded|Coperto
|
Shrouded|Coperto
|
||||||
|
|||||||
@@ -363,6 +363,7 @@ Shaft Up|As omhoog
|
|||||||
Shape|Vorm
|
Shape|Vorm
|
||||||
Shapes|Vormen
|
Shapes|Vormen
|
||||||
Show Grid|Raster weergeven
|
Show Grid|Raster weergeven
|
||||||
|
Show Resize Dimensions|Grootte-aanpassingsafmetingen weergeven
|
||||||
Show Rulers|Linialen weergeven
|
Show Rulers|Linialen weergeven
|
||||||
Shroud|Beschermrand
|
Shroud|Beschermrand
|
||||||
Shrouded|Afgeschermd
|
Shrouded|Afgeschermd
|
||||||
|
|||||||
@@ -351,6 +351,7 @@ Shaft Up|Jogar para cima
|
|||||||
Shape|Forma
|
Shape|Forma
|
||||||
Shapes|Formas
|
Shapes|Formas
|
||||||
Show Grid|Mostrar Grid
|
Show Grid|Mostrar Grid
|
||||||
|
Show Resize Dimensions|Mostrar Dimensões de Redimensionamento
|
||||||
Show Rulers|Mostrar Réguas
|
Show Rulers|Mostrar Réguas
|
||||||
Shroud|Envoltura
|
Shroud|Envoltura
|
||||||
Shrouded|Envolto
|
Shrouded|Envolto
|
||||||
|
|||||||
@@ -344,6 +344,7 @@ Shaft Up|Osovina Gore
|
|||||||
Shape|Oblik
|
Shape|Oblik
|
||||||
Shapes|Oblici
|
Shapes|Oblici
|
||||||
Show Grid|Prikaz Rešetke
|
Show Grid|Prikaz Rešetke
|
||||||
|
Show Resize Dimensions|Prikaz Dimenzija Promene Veličine
|
||||||
Show Rulers|Prikaz Lenjira
|
Show Rulers|Prikaz Lenjira
|
||||||
Shroud|Kućište
|
Shroud|Kućište
|
||||||
Shrouded|Sa Kućištem
|
Shrouded|Sa Kućištem
|
||||||
|
|||||||
@@ -352,6 +352,7 @@ Shape|आकार
|
|||||||
Shapes|आकार
|
Shapes|आकार
|
||||||
Show Bracket|ब्रैकेट दिखाएं
|
Show Bracket|ब्रैकेट दिखाएं
|
||||||
Show Grid|ग्रिड दिखाएं
|
Show Grid|ग्रिड दिखाएं
|
||||||
|
Show Resize Dimensions|आकार बदलने के आयाम दिखाएं
|
||||||
Show Rulers|रूलर दिखाएं
|
Show Rulers|रूलर दिखाएं
|
||||||
Shroud|श्राउड
|
Shroud|श्राउड
|
||||||
Shrouded|श्राउडेड
|
Shrouded|श्राउडेड
|
||||||
|
|||||||
@@ -352,6 +352,7 @@ Shape|形状
|
|||||||
Shapes|形状
|
Shapes|形状
|
||||||
Show Bracket|显示支架
|
Show Bracket|显示支架
|
||||||
Show Grid|显示网格
|
Show Grid|显示网格
|
||||||
|
Show Resize Dimensions|显示调整大小尺寸
|
||||||
Show Rulers|显示标尺
|
Show Rulers|显示标尺
|
||||||
Shroud|护罩
|
Shroud|护罩
|
||||||
Shrouded|带护罩
|
Shrouded|带护罩
|
||||||
|
|||||||
Reference in New Issue
Block a user