double click to instant creation

This commit is contained in:
Bane Stojkovic
2026-09-13 21:18:43 +02:00
parent 823a59d455
commit 556dedc9a3
5 changed files with 60 additions and 42 deletions
@@ -82,7 +82,8 @@ public class StatusBar extends JPanel implements IPlugIn {
private static final String HOLD_TO_UNSTUCK = LangUtil.translate("hold %s and drag to unstick from");
private static final String SELECTION = LangUtil.translate("Selection");
private static final String DRAG_POINTS_OF = LangUtil.translate("Drag control point(s) of");
private static final String DRAG_TO_PLACE_A_NEW = LangUtil.translate("Drag the mouse over the canvas to place a new");
private static final String DRAG_TO_PLACE_A_NEW =
LangUtil.translate("Click or drag over the canvas to place a new");
private static final String ZOOM = LangUtil.translate("Zoom");
private static final String SELECTION_SIZE = LangUtil.translate("Selection Size");
private static final String SELECTION_IS_EMPTY = LangUtil.translate("Selection is empty.");
@@ -94,6 +94,19 @@ public class ComponentButtonFactory {
button.addMouseListener(new MouseAdapter() {
/**
* Runs after the button has already fired its action for this click, so re-arming the slot
* here is what decides the mode: a double click instantiates the component up front so that
* it follows the cursor and drops in a single gesture, the way dragging it onto the canvas
* does, instead of asking for a point at a time.
*/
@Override
public void mouseClicked(MouseEvent e) {
if (SwingUtilities.isLeftMouseButton(e) && e.getClickCount() > 1) {
plugInPort.setNewComponentTypeSlot(componentType, null, null, true);
}
}
@Override
public void mousePressed(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON3) {
@@ -123,13 +123,7 @@ public class CustomTreeModel implements TreeModel {
if (fav.getType() == FavoriteType.Component) {
ComponentType type = this.typesByClass.get(fav.getName());
if (this.searchText == null || type.getName().toLowerCase().contains(this.searchText)) {
visibleTypes.add(new TreeNode(type, new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
plugInPort.setNewComponentTypeSlot(type, null, null, false);
}
}));
visibleTypes.add(new TreeNode(type, createComponentClickListener(type)));
}
} else {
// block
@@ -189,13 +183,7 @@ public class CustomTreeModel implements TreeModel {
if (type == null)
continue;
if (this.searchText == null || type.getName().toLowerCase().contains(this.searchText)) {
visibleTypes.add(new TreeNode(type, new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
plugInPort.setNewComponentTypeSlot(type, null, null, false);
}
}));
visibleTypes.add(new TreeNode(type, createComponentClickListener(type)));
}
}
}
@@ -230,17 +218,29 @@ public class CustomTreeModel implements TreeModel {
|| category.toLowerCase().contains(this.searchText.toLowerCase()) ||
typeMatches(this.searchText, type))
visibleTypes.add(new TreeNode(type, new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
plugInPort.setNewComponentTypeSlot(type, null, null, false);
}
}));
visibleTypes.add(new TreeNode(type, createComponentClickListener(type)));
this.visibleLeaves.put(category, visibleTypes);
return visibleTypes;
}
/**
* Arms the slot for the specified type. A double click instantiates the component up front so
* that it follows the cursor and drops in a single gesture, the way dragging it onto the canvas
* does, instead of asking for a point at a time.
*
* @param type
* @return listener to attach to the tree node.
*/
private MouseAdapter createComponentClickListener(ComponentType type) {
return new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
plugInPort.setNewComponentTypeSlot(type, null, null, e != null && e.getClickCount() > 1);
}
};
}
private boolean typeMatches(String searchText, ComponentType type) {
if (searchText == null || searchText.isEmpty())
return true;
@@ -258,17 +258,15 @@ public class TreePanel extends JPanel {
/**
* Prefer release over click: {@code mouseClicked} is not posted if the cursor moves
* between press and release (common with DnD or hand jitter), while selection may still
* change — then re-clicks on the same row fire no selection event.
* change - then re-clicks on the same row fire no selection event. Every release is
* forwarded rather than only the first, so that the listener can tell a double click from
* a single one; re-arming the slot on the second release is harmless.
*/
@Override
public void mouseReleased(MouseEvent e) {
if (SwingUtilities.isRightMouseButton(e) || e.isPopupTrigger()) {
return;
}
if (e.getClickCount() != 1) {
return;
}
TreePath path = tree.getPathForLocation(e.getX(), e.getY());
if (path == null) {
path = tree.getClosestPathForLocation(e.getX(), e.getY());