In my small visual editor, I want to be able to provide something not available in Matisse—the ability to resize selected widgets together as a single unit. I.e., not only "group move", but also "group resize". That would result in a proportional resize of related widgets.
However, the problem is, what if the resize of the main widget (i.e., the first selected widget, the one that determines the size that the other selected widgets will be resized to) causes the other selected widgets to disappear, i.e., if they become too small? Maybe that's why this isn't implemented in Matisse.
Anyway, here's my solution. The group resize works, though the prevention of disappearing secondary selected widgets is a bit hacky. public final class ResizeStrategyProvider implements ResizeProvider, ResizeStrategy { private final EditorComponentGraphScene scene; private int originalHeight; private int originalWidth; private HashMap selectedWidgetBoundsList = new HashMap(); public ResizeStrategyProvider(EditorComponentGraphScene scene) { this.scene = scene; } @Override public Rectangle boundsSuggested( Widget widget, Rectangle originalBounds, Rectangle suggestedBounds, ControlPoint cp) { //As the bounds change, get all the selected objects //and add their current bounds to the list: for (Object o : scene.getSelectedObjects()) { Widget w = scene.findWidget(o); selectedWidgetBoundsList.put(w, w.getBounds()); } return suggestedBounds; } @Override public void resizingStarted(Widget widget) { //When the resize starts, set the original height and width //of the main widget, so that it can be used later to //calculate how much the selected widgets should change //after the resize of the main widget: originalHeight = widget.getBounds().height; originalWidth = widget.getBounds().width; } @Override public void resizingFinished(Widget mainWidget) { for (Entry entry : selectedWidgetBoundsList.entrySet()) { //Get the next selected widget from the map: Widget selectedWidget = entry.getKey(); //Check that it isn't the main widget that's being resized: if (selectedWidget == mainWidget) { continue; } //Save our selected widget's original bounds: Rectangle originalBounds = selectedWidget.getBounds(); //Create a new rectangle for the new shape of our selected widget: Rectangle resizedRectOfSelectedWidget = new Rectangle(entry.getValue()); //Calculate the difference between the main widget's resized //height and width and the original height and width of the main widget: int diffHeight = mainWidget.getBounds().height - originalHeight; int diffWidth = mainWidget.getBounds().width - originalWidth; //Use the difference (whether positive or negative) to grow the rectangle: resizedRectOfSelectedWidget.grow(diffWidth, diffHeight); //However, let's protect the user and ensure that resizing //of the main widget won't cause any selected widgets to disappear //because of being too small as a result of the resize: if (resizedRectOfSelectedWidget.getBounds().width > 10 && resizedRectOfSelectedWidget.getBounds().height > 10) { selectedWidget.setPreferredBounds(resizedRectOfSel ectedWidget); } else if (resizedRectOfSelectedWidget.getBounds().width < 10 || resizedRectOfSelectedWidget.getBounds().height < 10) { StatusDisplayer.getDefault().setStatusText("Resizing further would " + "make your widget disappear..."); //Revert to original bounds: selectedWidget.setPreferredBounds(originalBounds); } } //Clear the list of selected widgets so that the list can be repopulated //when the next resize needs to be handled: selectedWidgetBoundsList.clear(); } }
Attach to the widget like this: ResizeStrategyProvider rsp = new ResizeStrategyProvider(scene); getActions().addAction(ActionFactory.createResizeA ction(rsp, rsp));