Grasshopper

algorithmic modeling for Rhino

Currently working on a new component, but is having some trouble changing the size of the original Bounds, using the Custom Attributes class.

I am actually rendering a new capsule over the old capsule, as this allows me the ability to add text real-time to the component, like so:

The bounds of the new capsule is determined by the bounds of the old component, like so:

textButtonBounds = new RectangleF(Bounds.X, Bounds.Y, Bounds.Width, Bounds.Height);
Bounds = new RectangleF(Bounds.X, Bounds.Y, Bounds.Width, Bounds.Height);

My question is, how do I change the bounds of my default component manually? As you can tell above, if the string is too long, it gets cut off. I am interested in it scaling to the text, which I know how to do, but I don't know what allows me to set the Bounds.X or Bounds.Y size.

I have tried:

Bounds.X += 10;

However, Bounds.X only has a getter, and no setter.

Views: 839

Replies to This Discussion

There's two problems here, one difficult, one fundamental. Let's start with the fundamental one.

The Bounds property is get/set and it is of type RectangleF. RectangleF has a get/set property for X. So it's not true that Bounds.X is only a getter. However it does behave as though it is. This is because RectangleF is a Value Type instead of a Reference Type. When you assign a variable of one value type to another variable of the same type, you always assign a copy of the first value. So when you request the Bounds from an attributes class, what you get is a copy of the actual bounds. Changing the X on this copy would be a useless operation which is why Visual Studio catches this mistake.

Let's assume that Dog is a class (a reference type) and it has a get/set property for fur type. Then, if I type:

Dog A = new Dog();

A.Coat = Long;

Dog B = A;

B.Coat = Short;

At the end of these lines, both A and B have a short coat, because the act of assigning A to B (line 3) means that both A and B now point to the same instance of Dog in memory. In effect, A and B are the same. If Dog were a struct (a value type), then at the end of this code A and B would have different coats, because assigning A to B means creating a copy of A. Any changes made to B will not affect A.

The one place where this causes annoying situations is exactly where you ran into it. If a property returns a value type then it's typically not useful to call properties and methods on that returned data, as it would only affect the copy of the actual data instead of the original data. That's why, if you want to change the Bounds of an attribute, you need code like this:

RectangleF box = Bounds;

box.X +=10;

Bounds = box;

On to the second problem, which is that doing it this way won't help you one bit. Laying out a component is a difficult job and the size of the Bounds depends on many things: 

  • The display mode of the component (icon or text).
  • The size of the text (depending on which Font to use).
  • The maximum number of input and output parameters.
  • The maximum width of the longest input/output parameter name.
  • The maximum number of state icons to draw on the input/output parameters.

Changing the Bounds after the layout has occurred will basically just invalidate the parameter layout, resulting in parameter names and grips being drawn in the wrong places.

If you want to affect the size of the Bounds for a GH_Component class, you're going to have to dive in and do the laying out yourself. As mentioned before, this is not trivial.

There are static methods on GH_ComponentAttributes which are helpful when doing this, have a look at:

LayoutComponentBox()

LayoutInputParams()

LayoutOutputParams()

LayoutBounds()

Unfortunately they are undocumented.

--

David Rutten

david@mcneel.com

Again, this is easier to do if you have a class which implements IGH_Param instead of IGH_Component, because a parameter is just one object, whereas a component is lots of objects that have to move and scale together.

You can probably do it by adjusting the bounds of the attributes afterwards, but it's still a bit tricky. I think the steps are as follows:

  1. Use the native Layout logic of the GH_ComponentAttributes.
  2. Measure the length of the string you need to display.
  3. Figure out how much wider you need to make the component bounds to cater for this text.
  4. Get the Bounds of the component attributes, change the Width and re-assign it.
  5. Get the Bounds of all the output parameter attributes, move it to the right (by changing the X property) and re-assign them.

--

David Rutten

david@mcneel.com

RSS

About

Translate

Search

Photos

  • Add Photos
  • View All

Videos

  • Add Videos
  • View All

© 2024   Created by Scott Davidson.   Powered by

Badges  |  Report an Issue  |  Terms of Service