X

Geertjan's Blog

  • October 6, 2009

Multiple Resize in Small Visual Bean Editor

Geertjan Wielenga
Product Manager
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<Widget, Rectangle> selectedWidgetBoundsList = new HashMap<Widget, Rectangle>();
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<Widget, Rectangle> 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(resizedRectOfSelectedWidget);
} 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.createResizeAction(rsp, rsp));

Join the discussion

Comments ( 3 )
  • Bernd Ruehlicke Wednesday, October 7, 2009

    Great stuff Geertjan. I have also pretty good fun with a MultiResizeProvider/Strategy. But I run into a very uncomfortable bug, which Sun Developer Expert Assistance team also confirmed for me after I entered a support request. They created a bug issue:

    http://www.netbeans.org/issues/show_bug.cgi?id=173997 (and http://forums.netbeans.org/topic18097.html )

    I wonder if you have similar issues ? Or maybe you do not need the widget location and hence not being impacted ?


  • Geertjan Thursday, October 8, 2009

    Hi Bernd, I haven't had that problem, but will look at it (maybe I didn't know I had that problem). By the way, how do you solve the problem of the secondary widgets disapearing? I.e., I select widget1, and then I select widget2 and widget3. Then I start making widget1 smaller, and so widget2 and widget3 get smaller too. But what happens if widget2 and widget3 were smaller than widget1 to begin with? How do you prevent them from becoming too small while making widget1 smaller???


  • Bernd Ruehlicke Thursday, October 8, 2009

    In my situation I have 4 widgets each having the exact same size to start out with. I.e. I do not run into the problem with widgets disappearing. You could give them a ResizeBorder with the control points on the outside. Then, when the widget should disappear the user would just see the controlpoint stay behind.I.e. the widget is gone but the user can still see that there is a widget - just infinitesimal small.


Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.